googleprojectzero / winafl

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

No expected output when using standalone debug mode of WinAFL client #442

Open steppanovva opened 3 months ago

steppanovva commented 3 months ago

Greetings,

Ran into a problem and unfortunately have no idea what the mistake i make. Any help to resolve this issue would be greatly appreciated. I am attaching afl.target.exe.22576.0000.proc.log Source code of test.cpp can be found at the very end of the issue.

If needed, I will provide any more information.

Description

  1. DynamoRIO version: DynamoRIO-Windows-10.0.0 (x64)
  2. System: Windows 10-2009 x64
  3. Application: simple programm, reads a number from file, creates array with size equal to this number and outputs it.
  4. Steps to reproduce:
    • Download and extract DynamoRIO
    • Compile target program: g++ test.cpp -o target. G++ version is 12.2.0
    • Run command C:\Users\stepanova.anna\dev\projects\winafl\DynamoRIO-Windows-10.0.0\bin64\drrun.exe -c ..\winafl.dll -debug -target_module target.exe -target_offset 0x1a60 -fuzz_iterations 10 -nargs 2 -- target.exe .\input\1

Output

None

Expected output - 10 times (due to fuzz_iterations option = 10) text below:

call target_function
File is open
File is closed
Size is read: 4
Array is filled
0 1 2 3
Array should be printed here
Array deleted

Log file output afl.target.exe.22576.0000.proc

Module loaded, dynamorio.dll
Module loaded, winafl.dll
Module loaded, drx.dll
Module loaded, drreg.dll
Module loaded, drmgr.dll
Module loaded, drwrap.dll
Module loaded, target.exe
Module loaded, libstdc++-6.dll
Module loaded, libgcc_s_seh-1.dll
Module loaded, libwinpthread-1.dll
Module loaded, KERNELBASE.dll
Module loaded, ucrtbase.dll
Module loaded, KERNEL32.dll
Module loaded, ntdll.dll
Module loaded, msvcrt.dll
Module loaded, RPCRT4.dll
Module loaded, bcrypt.dll
Module loaded, SECHOST.dll
Module loaded, ADVAPI32.dll
Module loaded, WTSAPI32.dll
Module loaded, siph64.dll
Module loaded, AppCore.dll
Module loaded, PluginAPI64.dll
Module loaded, SIHLib64.dll
In OpenFileW, reading \\.\{6BBFB4A2-B809-4194-8ED1-C0DA5D6B7429}
Module loaded, msvcp_win.dll
Module loaded, combase.dll
Module loaded, OLEAUT32.dll
Module loaded, WS2_32.dll
Module loaded, HdeSvc_p64.dll
Module loaded, WINSTA.dll
Module loaded, IPHLPAPI.DLL
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
Everything appears to be running normally.
Coverage map follows:

Handlers are called 10 times but no console output and an empty coverage map

To be mentioned

1. Target is running correctly without instrumentation. Command: target .\input\1 Output:

call target_function
File is open
File is closed
Size is read: 4
Array is filled
0 1 2 3
Array should be printed here
Array deleted

2. Target seems to be running correctly with command C:\Users\stepanova.anna\dev\projects\winafl\DynamoRIO-Windows-10.0.0\bin64\drrun.exe -debug -- target .\input\1 See expected output but have no idea what threads are mentioned at the end. Output:

<Starting application C:\Users\stepanova.anna\dev\projects\winafl\build64\bin\Release\app\target.exe (13780)>
<Running on newer-than-this-build "Microsoft Windows 10-2009 x64">
<Early threads found>
<Initial options = -no_dynamic_options -code_api -probe_api -stack_size 56K -max_elide_jmp 0 -max_elide_call 0 -no_inline_ignored_syscalls -native_exec_default_list '' -no_native_exec_managed_code -no_indcall2direct >
<CURIOSITY : instr_get_opcode(instr_new) != instr_get_opcode(instr_old) in file D:\a\dynamorio\dynamorio\core\win32\callback.c line 2079
version 10.0.0, custom build
-no_dynamic_options -code_api -probe_api -stack_size 56K -max_elide_jmp 0 -max_elide_call 0 -no_inline_ignored_syscalls -native_exec_default_list '' -no_native_exec_managed_code -no_indcall2direct
C:\Users\stepanova.anna\dev\projects\winafl\DynamoRIO-Windows-10.0.0/lib64\debug\dynamorio.dll=0x0000000015000000>
<CURIOSITY : instr_new == instrlist_first(ilist) || instr_new == instr_get_next(instrlist_first(ilist)) in file D:\a\dynamorio\dynamorio\core\win32\callback.c line 2082
version 10.0.0, custom build
-no_dynamic_options -code_api -probe_api -stack_size 56K -max_elide_jmp 0 -max_elide_call 0 -no_inline_ignored_syscalls -native_exec_default_list '' -no_native_exec_managed_code -no_indcall2direct
C:\Users\stepanova.anna\dev\projects\winafl\DynamoRIO-Windows-10.0.0/lib64\debug\dynamorio.dll=0x0000000015000000>
<Cleaning hooked Nt wrapper @0x00007ffd16bf08d0 sysnum=0x1c2>
<curiosity: rex.w on OPSZ_6_irex10_short4!>
<spurious rep/repne prefix @0x00007ffd16bf1d4a (f3 0f c7 f9): >
<CURIOSITY : (thread_lookup(tid) != ((void *)0) || check_filter("win32.suspend.exe;runall.detach_test.exe;" "win32.threadinjection.exe", get_short_name(get_application_name()))) && "app suspending unknown thread" in file D:\a\dynamorio\dynamorio\core\win32\syscall.c line 3607
version 10.0.0, custom build
-no_dynamic_options -code_api -probe_api -stack_size 56K -max_elide_jmp 0 -max_elide_call 0 -no_inline_ignored_syscalls -native_exec_default_list '' -no_native_exec_managed_code -no_indcall2direct
0x000000c30a9fec29 0xf000007ffce2a5b4
C:\Users\stepanova.anna\dev\projects\winafl\DynamoRIO-Windows-10.0.0/lib64\debug\dynamorio.dll=0x0000000015000000>
call target_function
File is open
File is closed
Size is read: 4
Array is filled
0 1 2 3
Array should be printed here
Array deleted
<Stopping application C:\Users\stepanova.anna\dev\projects\winafl\build64\bin\Release\app\target.exe (13780)>
<Failed to suspend attached-but-never-scheduled thread 18160>
<Failed to suspend attached-but-never-scheduled thread 17500>
<Failed to suspend attached-but-never-scheduled thread 12648>

test.cpp

#include <iostream>
#include <fstream>

int target_function(const char* filename) {
    std::ifstream file(filename);
    if (!file.is_open()) {
        std::cout << "Error while opening file" << std::endl;
        return 1;
    }
    std::cout << "File is open" << std::endl;

    int size;
    file >> size;
    file.close();
    if (!file.is_open()) {
        std::cout << "File is closed" << std::endl;
    }
    std::cout << "Size is read: " << size << std::endl;
    int* array = new int[size];

    for (int i = 0; i < size; ++i) {
        array[i] = i;
    }

    std::cout << "Array is filled" << std::endl;
    for (int i = 0; i < size; ++i) {
        std::cout << array[i] << " ";
    }
    std::cout << std::endl;
    std::cout << "Array should be printed here" << std::endl;

    delete[] array;
    std::cout << "Array deleted" << std::endl;

    return 0;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cout << "Provide filename as a parameter" << std::endl;
        return 1;
    }

    std::cout << "call target_function" << std::endl;
    return target_function(argv[1]);

}
ifratric commented 3 months ago

Hmm, IIRC afl-fuzz will mute output by default, but running DynamoRIO with winafl.dll directly should not. Does switching to latest DynamoRIO from https://github.com/DynamoRIO/dynamorio/releases help? Note: You might need to rebuild winafl.

steppanovva commented 3 months ago

Tackled this problem (I used previous binary compiled without -g flag, so apparently instruments were unable to locate main() correctly).

Now the output of C:\Users\stepanova.anna\dev\projects\winafl\DynamoRIO-Windows-10.0.0\bin64\drrun.exe -c ..\winafl.dll -debug -target_module target.exe -target_offset 0x1cf3 -fuzz_iterations 10 -nargs 2 -- target.exe .\input\1.txt is absolutely correct. Ten times text below:

call target_function
File is open
File is closed
Size is read: 4
Array is filled
0 1 2 3
Array should be printed here
Array deleted

But now, when I try to run afl-fuzz.exe with command: ..\afl-fuzz.exe -i .\input -o .\output -D C:\Users\stepanova.anna\dev\projects\winafl\DynamoRIO-Windows-10.0.0\bin64 -t 20000 -- -coverage_module target -target_module target -target_offset 0x1cf3 -fuzz_iterations 5000 -nargs 2 -- target.exe @@

I result in an error:

[-] PROGRAM ABORT : Test case 'id_000000' results in a timeout
Location : perform_dry_run(), C:\Users\stepanova.anna\dev\projects\winafl\afl-fuzz.c:3254

As I understand, it usually happens when debug mode is working uncorrectly but it is not the case this time. Don't you know what the problem can be? Maybe I have missed some crucial points?

Full output:

WinAFL 1.17 by <ifratric@google.com>
Based on AFL 2.43b by <lcamtuf@google.com>
[+] You have 16 CPU cores with average utilization of 0%.
[+] 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 '.\input'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Attempting dry run with 'id_000000'...

[-] The program took more than 20000 ms to process one of the initial test cases.
    In WinAFL, this error could also mean incorrect instrumentation params.
    Please make sure instrumentation runs correctly using the debug mode
    (see the README) before attempting to run afl-fuzz.

[-] PROGRAM ABORT : Test case 'id_000000' results in a timeout
         Location : perform_dry_run(), C:\Users\stepanova.anna\dev\projects\winafl\afl-fuzz.c:3254
ifratric commented 2 months ago

The only thing I notice is that in afl-fuzz command line, you use target instead of target.exe.

One thing you might try is using TinyInst instead of DynamoRIO instrumentation. TinyInst mode makes it easier to diagnose some issues IMO, in the above case it will tell you a real reason why the run hanged. You need to compile with -DTINYINST=1, the usage is similar to DR but some flags are slightly different / have different names. See https://github.com/googleprojectzero/winafl/blob/master/readme_tinyinst.md for usage examples.