{"id":299,"date":"2025-12-22T16:30:15","date_gmt":"2025-12-22T16:30:15","guid":{"rendered":"https:\/\/haco.club\/?p=299"},"modified":"2025-12-22T16:30:15","modified_gmt":"2025-12-22T16:30:15","slug":"afl_skip_bin_check","status":"publish","type":"post","link":"https:\/\/haco.club\/?p=299","title":{"rendered":"AFL_SKIP_BIN_CHECK"},"content":{"rendered":"\n<p><code>export AFL_SKIP_BIN_CHECK=1<\/code> is an environment variable setting that <strong>tells AFL++ to stop complaining that your target program doesn&#8217;t look like it was compiled with AFL.<\/strong><\/p>\n\n\n\n<p>By default, AFL++ checks your target binary for specific &#8220;instrumentation&#8221; markers before it starts. If it doesn&#8217;t find them, it assumes you made a mistake (like compiling with <code>gcc<\/code> instead of <code>afl-cc<\/code>) and refuses to run to save you from wasting time.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">When should you use this?<\/h3>\n\n\n\n<p>You generally <strong>should not<\/strong> use this unless you know exactly why. However, here are the valid scenarios where it is required:<\/p>\n\n\n\n<p><strong>1. You are fuzzing a script (Python, Bash, etc.)<\/strong><br>AFL++ is designed for compiled binaries (C\/C++). If you are using a wrapper to fuzz a Python script, AFL checks the wrapper (e.g., <code>\/usr\/bin\/python<\/code>), sees it wasn&#8217;t compiled with <code>afl-cc<\/code>, and errors out.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Solution:<\/strong> Set <code>AFL_SKIP_BIN_CHECK=1<\/code> so AFL++ ignores that the python binary isn&#8217;t instrumented, trusting that your wrapper handles the fuzzing logic.<\/li>\n<\/ul>\n\n\n\n<p><strong>2. You are using &#8220;Blackbox&#8221; Fuzzing (QEMU\/Frida mode)<\/strong><br>Sometimes when using QEMU mode (<code>-Q<\/code>) or Frida mode to fuzz a binary you don&#8217;t have source code for, AFL++ might still fail the initial check because the binary looks &#8220;weird&#8221; or stripped.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Solution:<\/strong> Setting this bypasses the check so QEMU can handle the instrumentation dynamically.<\/li>\n<\/ul>\n\n\n\n<p><strong>3. You are using a custom wrapper<\/strong><br>If you wrote a C program that calls another program, or a shell script that pipes input to a binary, AFL++ might not detect the instrumentation in the final target.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Danger<\/h3>\n\n\n\n<p>If you set this variable when you are <strong>NOT<\/strong> in one of the above special scenarios, AFL++ will run, but <strong>it will not find any bugs.<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>It will run the program blindly.<\/li>\n\n\n\n<li>It will not receive coverage feedback (it won&#8217;t know which inputs are &#8220;good&#8221;).<\/li>\n\n\n\n<li>It will effectively be a random number generator throwing garbage at your program, which is extremely inefficient.<\/li>\n<\/ul>\n\n\n\n<p><strong>Summary:<\/strong> Only use <code>export AFL_SKIP_BIN_CHECK=1<\/code> if AFL++ refuses to run <em>and<\/em> you are sure you are using a special fuzzing mode (like scripts or binary-only) where standard instrumentation is not expected.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>The specific &#8220;instrumentation&#8221; markers AFL++ checks<\/strong><\/p>\n\n\n\n<p>AFL++ checks for <strong>two types<\/strong> of markers: <strong>Static Symbols<\/strong> (variables in the binary) and <strong>Runtime Behavior<\/strong> (the forkserver handshake).<\/p>\n\n\n\n<p>When you set <code>AFL_SKIP_BIN_CHECK=1<\/code>, you are telling AFL++ to ignore the absence of both.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. Static Markers (Symbols)<\/h3>\n\n\n\n<p>AFL++ inspects your binary (roughly equivalent to running <code>nm<\/code> or <code>readelf<\/code>) to see if specific variables injected by the compiler exist. If they are missing, it assumes the binary was compiled with standard <code>gcc<\/code> instead of <code>afl-cc<\/code>.<\/p>\n\n\n\n<p>The most critical symbols it looks for are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>__afl_area_ptr<\/code><\/strong>: This is a pointer to the &#8220;Shared Memory&#8221; map where code coverage is stored. It is the single most important variable for AFL.<\/li>\n\n\n\n<li><strong><code>__afl_prev_loc<\/code><\/strong>: A thread-local variable that stores the ID of the <em>previous<\/em> basic block executed (used to calculate edge coverage: A -> B).<\/li>\n\n\n\n<li><strong><code>__afl_map_size<\/code><\/strong>: Stores the size of the coverage map (usually 64KB).<\/li>\n<\/ul>\n\n\n\n<p>If you strip your binary (using <code>strip<\/code>), these symbols might be removed from the symbol table, causing AFL++ to think the binary is not instrumented, even if it actually is.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. Runtime Markers (The Forkserver Handshake)<\/h3>\n\n\n\n<p>This is the functionality check. When <code>afl-fuzz<\/code> starts, it tries to &#8220;wake up&#8221; the instrumentation inside your target.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>The Handshake:<\/strong> AFL++ sends a signal to your target program via a specific file descriptor (Control Pipe, usually FD 198).<\/li>\n\n\n\n<li><strong>The Response:<\/strong> It expects the target to pause immediately (before <code>main<\/code> typically starts) and send exactly <strong>4 bytes<\/strong> back via another file descriptor (Status Pipe, usually FD 199).<\/li>\n<\/ol>\n\n\n\n<p>If the program just runs normally and doesn&#8217;t send those 4 bytes back, AFL++ concludes: &#8220;This program doesn&#8217;t have the forkserver built-in,&#8221; and aborts.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Summary<\/h3>\n\n\n\n<p>When you use <code>export AFL_SKIP_BIN_CHECK=1<\/code>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>It skips the symbol check:<\/strong> It won&#8217;t complain if <code>__afl_area_ptr<\/code> is missing.<\/li>\n\n\n\n<li><strong>It skips the handshake requirement:<\/strong> It will run the program blindly (using <code>execve<\/code> every time instead of the forkserver), which is much slower and provides no coverage feedback unless you are using QEMU (<code>-Q<\/code>) or Frida mode.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>export AFL_SKIP_BIN_CHECK=1 is an environment variable setting that tells AFL++ [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[42],"tags":[49],"class_list":["post-299","post","type-post","status-publish","format-standard","hentry","category-knowledge-base","tag-afl"],"_links":{"self":[{"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/posts\/299","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/haco.club\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=299"}],"version-history":[{"count":1,"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/posts\/299\/revisions"}],"predecessor-version":[{"id":300,"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/posts\/299\/revisions\/300"}],"wp:attachment":[{"href":"https:\/\/haco.club\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=299"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/haco.club\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=299"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/haco.club\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=299"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}