googleprojectzero / winafl

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

Is it possible to detect when the target exits with exit code != 0, and interpret this as a 'crash'? #380

Closed DanielEbert closed 2 years ago

DanielEbert commented 2 years ago

Hi,

I want to detect (and store the input) when my target program exits with an exit code that is not equal to 0.

Is this possible with winafl? If there is no build-in way to do this: Could you point me to the source code location where I can get the target program's exit code?

I use DynamoRIO, and 32 Bit mode.

ifratric commented 2 years ago

Good question. I think the best place to do it would be the event_exit() function

https://github.com/googleprojectzero/winafl/blob/master/winafl.c#L756

What you need to do to notify afl-fuzz of crash is send a special character C (indicating a crash) and the exception code over the pipe. See implementation of onexception() for example:

https://github.com/googleprojectzero/winafl/blob/master/winafl.c#L235

I never tried to do it myself so you'll have to experiment and see if that works.

DanielEbert commented 2 years ago

Thanks a lot for this info :)

With your info I found a solution that works for me: Add the following at the start of the post_fuzz_handler function:

if (drwrap_get_retval(wrapcxt) != 0) {
    WriteCommandToPipe('C');
    WriteDWORDCommandToPipe(STATUS_FATAL_APP_EXIT);
    dr_exit_process(1);
}

and set the afl-fuzz flag: -target_method main

What this does is it checks the return value of the main function. If this is != 0, we notify afl-fuzz and exit the target program. post_fuzz_handler is not called when the target program uses std::exit(exitcode), but winafl detects this as a 'hang' and stores the input, so that works for me. '-target_method main' is not necessary. You can use the Dynamorio API drwrap_wrap_ex to check the return value of any function you want, but this requires a bit more code.

I didn't use event_exit() because I didn't find out how to get the exit value in event_exit(). In addition, event_exit() is only called every fuzz_iterations iterations. So if I wanted to use that I think I'd have to set fuzz_iterations to 1.

ifratric commented 2 years ago

Yep, that looks good. FWIW I referenced event_exit() because you asked about a scenario where the program exits (and I assumed it would sometimes exit during target function and you wanted to catch that). If just looking at the target function return value is sufficient, then your solution does the trick :)

DanielEbert commented 2 years ago

Yes, for me looking at the target function return value is sufficient :) Thank you