googleprojectzero / winafl

A fork of AFL for fuzzing Windows binaries
Apache License 2.0
2.36k stars 533 forks source link

WinAFL can not fuzzy Windows service. #392

Open daniel0005fk168 opened 2 years ago

daniel0005fk168 commented 2 years ago

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

include

include

define _MY_DEBUGTAG "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 ifratric@google.com Based on AFL 2.43b by lcamtuf@google.com [+] 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 commented 2 years ago

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

daniel0005fk168 commented 2 years ago

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 commented 2 years ago

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

ifratric commented 2 years ago

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