Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WinAFL can not fuzzy Windows service. #392

Open
daniel0005fk168 opened this issue Oct 24, 2022 · 4 comments
Open

WinAFL can not fuzzy Windows service. #392

daniel0005fk168 opened this issue Oct 24, 2022 · 4 comments

Comments

@daniel0005fk168
Copy link

I have simple service and try to run fuzzy function but fuzzy never run. Below is my service code.

#include <Windows.h>
#include <tchar.h>

#define MY_DEBUG_TAG "SampleService"
#include "log.h"

SERVICE_STATUS g_ServiceStatus = {0};
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;

VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv);
VOID WINAPI ServiceCtrlHandler (DWORD);
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam);

#define SERVICE_NAME _T("SampleService")

DWORD g_BytesTransferred = 0;

VOID CALLBACK FileIOCompletionRoutine(
__in DWORD dwErrorCode,
__in DWORD dwNumberOfBytesTransfered,
__in LPOVERLAPPED lpOverlapped)
{
g_BytesTransferred = dwNumberOfBytesTransfered;
}

void __declspec(noinline) fuzz(LPCWSTR data) {
int const BUFFERSIZE = 1024;
DWORD dwBytesRead = 0;
char ReadBuffer[BUFFERSIZE] = { 0 };
OVERLAPPED ol = { 0 };

debug_print("fuzz open file = %s\n", data);
HANDLE hFile = CreateFile(data,
    GENERIC_READ,
    FILE_SHARE_READ,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
    NULL);

if (hFile == INVALID_HANDLE_VALUE)
{
    debug_print("fuzz open file error= %s\n", data);
    return;
}

if (FALSE == ReadFileEx(hFile, ReadBuffer, BUFFERSIZE - 1, &ol, FileIOCompletionRoutine))
{
    debug_print("fuzz read fil faile=%08x\n", GetLastError());
    CloseHandle(hFile);
    return;
}

//SleepEx(1000, TRUE);
dwBytesRead = g_BytesTransferred;

if (dwBytesRead > 0 && dwBytesRead <= BUFFERSIZE - 1)
{
    ReadBuffer[dwBytesRead] = '\0'; // NULL character
    debug_print("fuzz read OK=%s\n", ReadBuffer);
}
else if (dwBytesRead == 0)
{
    debug_print("fuzz read no data\n");
}
else
{
    debug_print("\n ** Unexpected value for dwBytesRead ** \n");
}

CloseHandle(hFile);
debug_print("fuzz finished\n");

}

int _tmain (int argc, TCHAR *argv[])
{
debug_print("Main: Entry");

debug_print("argc = %d\n", argc);
for (int i = 0; i < argc; i++)
    debug_print("argv[%d] = %s\n", i, argv[i]);

fuzz(L"D:\\WinAFL\\Test\\input.txt");

SERVICE_TABLE_ENTRY ServiceTable[] = 
{
    {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
    {NULL, NULL}
};

if (StartServiceCtrlDispatcher (ServiceTable) == FALSE)
{
   debug_print("Main: StartServiceCtrlDispatcher returned %d", GetLastError());
   return GetLastError ();
}

debug_print("Main: Exit");
return 0;

}

VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv)
{
DWORD Status = E_FAIL;

debug_print("ServiceMain: Entry");

HANDLE hDebuggerPresentThread = CreateThread(NULL, 0, DebuggerPresentThread, NULL, 0, NULL);

g_StatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler);

if (g_StatusHandle == NULL) 
{
    debug_print("ServiceMain: RegisterServiceCtrlHandler returned error");
    goto EXIT;
}

// Tell the service controller we are starting
ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;

if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) 
{
    debug_print("SetServiceStatus returned error");
}

/* 
 * Perform tasks neccesary to start the service here
 */
debug_print("Performing Service Start Operations");

// Create stop event to wait on later.
g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL) 
{
    debug_print("ServiceMain: CreateEvent(g_ServiceStopEvent) returned error");

    g_ServiceStatus.dwControlsAccepted = 0;
    g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
    g_ServiceStatus.dwWin32ExitCode = GetLastError();
    g_ServiceStatus.dwCheckPoint = 1;

    if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
    {
        debug_print("ServiceMain: SetServiceStatus returned error");
    }
    goto EXIT; 
}    

// Tell the service controller we are started
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;

if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
    debug_print("ServiceMain: SetServiceStatus returned error");
}

// Start the thread that will perform the main task of the service
HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);

debug_print("ServiceMain: Waiting for Worker Thread to complete");

// Wait until our worker thread exits effectively signaling that the service needs to stop
WaitForSingleObject (hThread, INFINITE);

debug_print("ServiceMain: Worker Thread Stop Event signaled");


/* 
 * Perform any cleanup tasks
 */
debug_print("ServiceMain: Performing Cleanup Operations");

CloseHandle (g_ServiceStopEvent);

g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;

if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
{
    debug_print("ServiceMain: SetServiceStatus returned error");
}

EXIT:
debug_print("ServiceMain: Exit");

return;

}

VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode)
{
debug_print("ServiceCtrlHandler: Entry");

switch (CtrlCode) 
{
 case SERVICE_CONTROL_STOP :

     debug_print("ServiceCtrlHandler: SERVICE_CONTROL_STOP Request");

    if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
       break;

    /* 
     * Perform tasks neccesary to stop the service here 
     */
    
    g_ServiceStatus.dwControlsAccepted = 0;
    g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 4;

    if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE)
	{
        debug_print("ServiceCtrlHandler: SetServiceStatus returned error");
	}

    // This will signal the worker thread to start shutting down
    SetEvent (g_ServiceStopEvent);

    break;

 default:
     break;
}

debug_print("ServiceCtrlHandler: Exit");

}

DWORD WINAPI ServiceWorkerThread (LPVOID lpParam)
{
debug_print("ServiceWorkerThread: Entry");

//  Periodically check if the service has been requested to stop
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
{        
    /* 
     * Perform main service function here
     */

    //  Simulate some work by sleeping
    Sleep(3000);
}

debug_print("ServiceWorkerThread: Exit");

return ERROR_SUCCESS;

}

It can run fuzzy on command
afl-fuzz.exe -D D:\WinAFL\DynamoRIO-Git\dynamorio\build\bin64\ -i D:\WinAFL\Test\testin -o D:\WinAFL\Test\testout -t 200000 -- -coverage_module SampleService.exe -target_module SampleService.exe -target_method fuzz -fuzz_iterations 10 -nargs 2 -- SampleService.exe @@

But can not run on command and it will stock "OverlappedConnectNamedPipe", "OverlappedConnectNamedPipe" is my log.
afl-fuzz.exe -D D:\WinAFL\DynamoRIO-Git\dynamorio\build\bin64\ -A SampleService.exe -i D:\WinAFL\Test\testin -o D:\WinAFL\Test\testout -t 200000 -- -coverage_module SampleService.exe -target_module SampleService.exe -target_method fuzz -fuzz_iterations 10 -nargs 2 -- SampleService.exe @@

WinAFL 1.16b by [email protected]
Based on AFL 2.43b by [email protected]
[+] You have 4 CPU cores with average utilization of 11%.
[+] Try parallel jobs - see afl_docs\parallel_fuzzing.txt.
[] Checking CPU core loadout...
[+] Found a free CPU core, binding to #0.
[+] Process affinity is set to 1.
[
] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[] Deleting old session data...
[+] Output dir cleanup successful.
[
] Scanning 'D:\WinAFL\Test\testin'...
[+] No auto-generated dictionary tokens to reuse.
[] Creating hard links for all input files...
[
] Attempting dry run with 'id_000000'...
[*] OverlappedConnectNamedPipe GetLastError=997

Please help me, There have any wrong let service can not run fuzzy.

@ifratric
Copy link
Collaborator

For fuzzing Windows services, you most likely want to use "Attach" functionality, see https://github.com/googleprojectzero/winafl#attaching-to-a-running-process

@daniel0005fk168
Copy link
Author

Yes, I am use attach by add option -A, But it seems no function. below is my command.

afl-fuzz.exe -D D:\WinAFL\DynamoRIO-Git\dynamorio\build\bin64\ -A SampleService.exe -i D:\WinAFL\Test\testin -o D:\WinAFL\Test\testout -t 200000 -- -coverage_module SampleService.exe -target_module SampleService.exe -target_method fuzz -fuzz_iterations 10 -nargs 2 -- SampleService.exe @@

fuzz function never run.

@fr0zenrain
Copy link

i have a question, As I know,In order to get coverage, the process must exit.so how winafl attach model work.Thanks!

@ifratric
Copy link
Collaborator

The process does not need to exit in order to get coverage. WinAFL collects coverage when the target_method exits, not the process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants