{
    "version": "https://jsonfeed.org/version/1",
    "title": "Michael&apos;s Weblog",
    "home_page_url": "http://mav.codes/",
    "feed_url": "http://mav.codes/feed.json",
    "description": "A security student's blog",
    "icon": "http://mav.codes/apple-touch-icon.png",
    "favicon": "http://mav.codes/favicon.ico",
    "expired": false,
    
    "author": "{"twitter"=>nil, "name"=>nil, "avatar"=>nil, "email"=>nil, "url"=>nil}",
    
"items": [
    
        {
            "id": "http://mav.codes/2022/05/12/solving-a-crackme-with-binary-ninja",
            "title": "Solving a Crackme with Binary Ninja",
            "summary": "The mechanics and process of writing an ELF executable virus",
            "content_text": "Binary NinjaI recently found out that Vector35 has a student discount for their reverse engineering suite Binary Ninja, which I eventually caved in on. It’s very good, especially for the price compared to IDA. To get more familiar with it, I checked out a crackme challenge. Crackmes are a fun way to learn and stay sharp with reverse engineering. I have a habit of looking on crackmes.one and getting sucked into these.Looking for some Linux challenges I found this one, Hash checker 0x01, by f0rizen. It was uploaded recently so I downloaded it and tossed it into Binary Ninja.ReversingGetting started, once you extract the binary and open it into Binary Ninja, it will start analyzing it. We can look at the main function and get a basic idea of what is going on.One of the most useful features of Ghidra and Binary Ninja is each included decompiler. Binary Ninja’s has several intermediate languages that you can choose from to look at the code, and offers both a linear and graph view for each. Looking at Linear view with the High Level IL (HLIL) output gives a high-level overview of the main function. It is similar to C code, but has some of its own shorthand for specific operations.There are a few things to note here:  It checks for there to be only one argument (1 + argv[0], the program path = 2)  The length of this single argument must be 6  There is some other validation function named “checker” that must return zeroIf any of these are not the case, the program shows the usage message circled below and exits.Inside the loops is a a lot of HLIL shorthand. It culminates with a conditional based on a local variable, called var_60_1 by Binary Ninja. This variable is mutated and must equal 0x3c0431a5 for the submitted key to be correct,  This is the hash mentioned in the challenge name - We need to pass an input of 6 bytes that is hashed to this value.We know the input must be six bytes long, but it also must pass the checker function.int64_t checker(char* key) {       int32_t counter = 0;    int64_t return_value;    while (true)    {        if (counter &gt;= strlen(key))        {            return_value = 1;            break;        }        if ((key[((int64_t)counter)] &gt; 47 &amp;&amp; \\             key[((int64_t)counter)] &lt;= 57))        {            counter = (counter + 1);            continue;        }        return_value = 0;        break;    }    return return_value;}After renaming some of the variables, and displaying the values used in the conditional as decimal numbers, it’s easier to see what the function is doing.It loops over the bytes in the string, and checks that each one is between 48 and 58 - on an ASCII table these are 0-9 digits.So going back to main, our input basically needs to be 6 ascii digits. This is only 1,000,000 possible combinations, so you could brute force this just from the shell if you wanted to, but that’s not really the spirit of the challenge. Instead we can drill down into what these two loops are doing, implement the hash function, and then brute force the hash.Loop SetupLooking at the block before the first loop, we can switch back to Disassembly view to see exactly what is going on:mov     rax, qword [rbp-0x80 {argv}]add     rax, 0x8mov     rax, qword [rax]mov     rdi, raxcall    strlenmov     dword [rbp-0x5c {input_length}], eaxmov     rax, qword [rbp-0x80 {argv}]mov     rax, qword [rax+0x8]mov     qword [rbp-0x50 {user_input}], raxmov     eax, dword [rbp-0x5c {input_length}]cdqe    sub     rax, 0x1mov     qword [rbp-0x48 {input_minus_one}], raxHere the length of argv[1] is saved, and the length-1 is saved into another variable that ultimately isn’t used.mov     eax, dword [rbp-0x5c {input_length}]cdqe    mov     r14, raxmov     r15d, 0x0mov     eax, dword [rbp-0x5c {input_length}]cdqe    mov     r12, raxmov     r13d, 0x0I couldn’t figure out what these instructions are doing, since r12-r15 aren’t actually used in this function. It could just be obfuscation by the author.What looks like some more obfuscation immediately follows, this time accessed and written to.mov     eax, dword [rbp-0x5c {input_length}]cdqe    lea     rdx, [rax*8] // 0x30mov     eax, 0x10sub     rax, 0x1add     rax, rdxmov     esi, 0x10mov     edx, 0x0div     rsiimul    rax, rax, 0x10sub     rsp, raxmov     rax, rspadd     rax, 0x7shr     rax, 0x3shl     rax, 0x3mov     qword [rbp-0x40 {seed_data_ptr}], raxmov     rax, qword [rbp-0x40 {seed_data_ptr}]mov     qword [rax], 0x1mov     dword [rbp-0x60 {counter}], 0x1Ultimately the stack pointer is subtracted by 0x30, then 7 is added to it. Finally two writes: this stack address is saved into a pointer and a one is placed there (at RAX). A variable later used as a counter (RBP-0x60) is also set to one.First LoopIn the first loop, we can see why.First, the counter is loaded, and then subtracted by one to load into EDX - this is used to calculate an offset from the pointer in the previous block. It is a 64 bit integer, so this is used as an offset from the pointer. On the first iteration, counter = 1, so this is the first (0th) element in the array.Next, that value is multiplied by 0x83, and then the remainder modulo 0x3b9aca09 is taken. Finally this is saved at the index marked by counter. In short, the loop is basically this:array[n] = array[n-1] * 0x83 % 0x3b9aca09You can do the math yourself, or just verify this in the debugger:Importantly, these numbers are computed on constants, based on a counter that has to be six - every time you run this program these numbers will be the same. Effectively, it’s just runtime obfuscation of both a pointer (the random bit shifting and saving to rbp-0x40) and the data at that pointer. Despite being generated at runtime it’s effectively static data.I called this seed data, thinking that this would be relevant in the hash calculation which occurs in the second loop. Knowing that we’re generating this data and seeing a reference to this pointer in the second loop, we can figure out what it is doing.Hash FunctionFirst some initialization is performed - After the first loop is finished, the first counter equals six, then the code follows a new block on the right where the hash is initalized with the first byte of the input. The loop only runs through the last five bytes, so this makes sure all of them factor into the hash.A second counter is set to 1, since index 0 of the input has already been stored in the hash variable.The inside of this loop runs five times, and does five main operations.  Get the current value of seed data (0x83 to start) into RCX  Get the corresponding byte of input into RAX  Get the remainder of dividing this byte (RAX) by 0x3db9aca09  Multiply this result by the seed value in RCX  Divide this by 0x3db9aca09, and add the remainder to the hashThis runs five times, eventually ending the loop with a comparison to the correct hash.Interestingly, the pre-initialization isn’t really necessary because starting from index zero will produce the same result. The first value % 0x3db9aca09 will equal itself, and multiplying that by the first value of seed data (0x1) has no effect. It’s not immediately clear if this is done by the author or the compiler.KeygenNow that we know both the hash and how it is computed, including the seed data/starting state values, we can write brute force any inputs that collide to this value. Since there are only one million possibilities, it can run in under a second.Starting off we can define some variables for us, including the seed data just as a list.import itertoolsHASH = 0x3c0431a5 # hash value of the input to match# valid characters, ASCII 0-9VALID = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']# generated by the first loop in main, always the sameseed = [0x1, 0x83, 0x4309, 0x224d9b, 0x118db651, 0x228a4e1d]Translating the steps into python, we can write a short loop to implement the hashing.def keyhash(s: str):    \"\"\"return the hash of the input\"\"\"    hashvalue = ord(s[0])    for i in range(1, len(s)):        seedval = seed[i]        b = ord(s[i]) # byte to use        rem = b % 0x3b9aca09        m = rem * seedval        frem = m % 0x3b9aca09        hashvalue += frem         return hashvalueJust like in the challenge binary, it would technically work if the hash was initialized to zero and the loop ran 6 times over the whole input, since the first iteration only multiplies the first value by one.We can then use itertools’ cartesian product function to brute force all of the keys and check against the hash value.def main():    for attempt in itertools.product(VALID, repeat=6):        test = \"\".join(attempt)        check = keyhash(test)        if check == HASH: # 0x3c0431a5            print(\"Solution:\", test, hex(check))    return 0After running this we can finally see:$ Solution: 231337 0x3c0431a5$ ./crackme 231337Key is valid$ No collisions, and a valid key.",
            "content_html": "<h2 id=\"binary-ninja\">Binary Ninja</h2><p>I recently found out that <a href=\"https://vector35.com/\">Vector35</a> has a student discount for their reverse engineering suite <a href=\"https://binary.ninja/\">Binary Ninja</a>, which I eventually caved in on. It’s very good, especially for the price compared to IDA. To get more familiar with it, I checked out a crackme challenge. <a href=\"https://en.wikipedia.org/wiki/Crackme\">Crackmes</a> are a fun way to learn and stay sharp with reverse engineering. I have a habit of looking on crackmes.one and getting sucked into these.</p><p>Looking for some Linux challenges I found <a href=\"https://crackmes.one/crackme/622db5be33c5d46c8bcc027f\">this one</a>, Hash checker 0x01, by <a href=\"https://crackmes.one/user/f0rizen\">f0rizen</a>. It was uploaded recently so I downloaded it and tossed it into Binary Ninja.</p><h2 id=\"reversing\">Reversing</h2><!-- Crackmes aren't supposed to have malware in them, but you're still trusting an executable downloaded from the internet.  --><p>Getting started, once you extract the binary and open it into Binary Ninja, it will start analyzing it. We can look at the main function and get a basic idea of what is going on.</p><p>One of the most useful features of Ghidra and Binary Ninja is each included decompiler. Binary Ninja’s has several intermediate languages that you can choose from to look at the code, and offers both a linear and graph view for each. Looking at Linear view with the High Level IL (HLIL) output gives a high-level overview of the main function. It is similar to C code, but has some of its own shorthand for specific operations.</p><p><img src=\"/assets/img/crackme_main.png\" alt=\"Main function in Binary Ninja, visible calls to a &quot;checker&quot; function with argv[1] as the parameter\" /></p><!-- ```cint main(int argc, char ** argv, char ** envp) {      char** argv = argv;      void* fsbase;      int64_t rax = *(int64_t*)((char*)fsbase + 0x28);      int32_t must_be_6;      int32_t is_numeric;      int32_t return_value;      if (argc == 2)      {          must_be_6 = strlen(argv[1]);          if (must_be_6 == 6)          {              is_numeric = checker(argv[1]);              if (is_numeric != 0)              {                  int32_t input_length = strlen(argv[1]);                  char* input_ptr = argv[1];                  int64_t input_minus_one = (((int64_t)input_length) - 1);                  *(int64_t*)rax_26 = 1;                  for (int32_t counter = 1; counter < input_length; counter = (counter + 1))                  {                      int64_t rax_31;                      int64_t rdx_6;                      rdx_6 = HIGHD(((int128_t)(0x83 * *(int64_t*)(rax_26 + (((int64_t)(counter - 1)) << 3)))));                      rax_31 = LOWD(((int128_t)(0x83 * *(int64_t*)(rax_26 + (((int64_t)(counter - 1)) << 3)))));                      *(int64_t*)(rax_26 + (((int64_t)counter) << 3)) = (COMBINE(rax_31, rax_31) % 0x3b9aca09);                  }                  // rcx = seed_value                  int64_t hash_value = ((int64_t)*(int8_t*)input_ptr);                  for (int32_t secound_counter = 1; secound_counter < input_length; secound_counter = (secound_counter + 1))                  {                      int64_t rax_46;                      int64_t rdx_14;                      // rax = (eax * seed_value) % 0x3b9aca09                      hash_value = (hash_value + (COMBINE(rax_46, rax_46) % 0x3b9aca09));                  // rax = (eax * seed_value) % 0x3b9aca09                  }                  if (hash_value != 0x3c0431a5)                  {                      puts(\"Wrong key!\");                  }                  else                  {                      puts(\"Key is valid\");                  }                  return_value = 0;              }          }      }      if (((argc != 2 || (argc == 2 && must_be_6 != 6)) || ((argc == 2 && must_be_6 == 6) && is_numeric == 0)))      {          puts(\"Usage: ./crackme XXXXXX\");          return_value = 1;      }      *(int64_t*)((char*)fsbase + 0x28);      if (rax == *(int64_t*)((char*)fsbase + 0x28))      {          return return_value;      }      __stack_chk_fail();      /* no return */  }``` --><p>There are a few things to note here:</p><ol>  <li>It checks for there to be only one argument (1 + argv[0], the program path = 2)</li>  <li>The length of this single argument must be 6</li>  <li>There is some other validation function named “checker” that must return zero</li></ol><p>If any of these are not the case, the program shows the usage message circled below and exits.</p><p>Inside the loops is a a lot of HLIL shorthand. It culminates with a conditional based on a local variable, called var_60_1 by Binary Ninja. This variable is mutated and must equal <strong>0x3c0431a5</strong> for the submitted key to be correct,  This is the hash mentioned in the challenge name - We need to pass an input of 6 bytes that is hashed to this value.</p><p>We know the input must be six bytes long, but it also must pass the checker function.</p><!-- ![While true loop over the input bytes, checking that all bytes are ascii digits](/assets/img/checker_function.png) --><div class=\"language-c highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kt\">int64_t</span> <span class=\"nf\">checker</span><span class=\"p\">(</span><span class=\"kt\">char</span><span class=\"o\">*</span> <span class=\"n\">key</span><span class=\"p\">)</span> <span class=\"p\">{</span>       <span class=\"kt\">int32_t</span> <span class=\"n\">counter</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>    <span class=\"kt\">int64_t</span> <span class=\"n\">return_value</span><span class=\"p\">;</span>    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"nb\">true</span><span class=\"p\">)</span>    <span class=\"p\">{</span>        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">counter</span> <span class=\"o\">&gt;=</span> <span class=\"n\">strlen</span><span class=\"p\">(</span><span class=\"n\">key</span><span class=\"p\">))</span>        <span class=\"p\">{</span>            <span class=\"n\">return_value</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span>            <span class=\"k\">break</span><span class=\"p\">;</span>        <span class=\"p\">}</span>        <span class=\"k\">if</span> <span class=\"p\">((</span><span class=\"n\">key</span><span class=\"p\">[((</span><span class=\"kt\">int64_t</span><span class=\"p\">)</span><span class=\"n\">counter</span><span class=\"p\">)]</span> <span class=\"o\">&gt;</span> <span class=\"mi\">47</span> <span class=\"o\">&amp;&amp;</span> \\             <span class=\"n\">key</span><span class=\"p\">[((</span><span class=\"kt\">int64_t</span><span class=\"p\">)</span><span class=\"n\">counter</span><span class=\"p\">)]</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">57</span><span class=\"p\">))</span>        <span class=\"p\">{</span>            <span class=\"n\">counter</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">counter</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">);</span>            <span class=\"k\">continue</span><span class=\"p\">;</span>        <span class=\"p\">}</span>        <span class=\"n\">return_value</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>        <span class=\"k\">break</span><span class=\"p\">;</span>    <span class=\"p\">}</span>    <span class=\"k\">return</span> <span class=\"n\">return_value</span><span class=\"p\">;</span><span class=\"p\">}</span></code></pre></div></div><p>After renaming some of the variables, and displaying the values used in the conditional as decimal numbers, it’s easier to see what the function is doing.</p><p>It loops over the bytes in the string, and checks that each one is between 48 and 58 - on an ASCII table these are 0-9 digits.</p><p>So going back to main, our input basically needs to be 6 ascii digits. This is only 1,000,000 possible combinations, so you could brute force this just from the shell if you wanted to, but that’s not really the spirit of the challenge. Instead we can drill down into what these two loops are doing, implement the hash function, and then brute force the hash.</p><h2 id=\"loop-setup\">Loop Setup</h2><p>Looking at the block before the first loop, we can switch back to Disassembly view to see exactly what is going on:</p><pre><code class=\"language-x86asm\">mov     rax, qword [rbp-0x80 {argv}]add     rax, 0x8mov     rax, qword [rax]mov     rdi, raxcall    strlenmov     dword [rbp-0x5c {input_length}], eaxmov     rax, qword [rbp-0x80 {argv}]mov     rax, qword [rax+0x8]mov     qword [rbp-0x50 {user_input}], raxmov     eax, dword [rbp-0x5c {input_length}]cdqe    sub     rax, 0x1mov     qword [rbp-0x48 {input_minus_one}], rax</code></pre><p>Here the length of argv[1] is saved, and the length-1 is saved into another variable that ultimately isn’t used.</p><pre><code class=\"language-x86asm\">mov     eax, dword [rbp-0x5c {input_length}]cdqe    mov     r14, raxmov     r15d, 0x0mov     eax, dword [rbp-0x5c {input_length}]cdqe    mov     r12, raxmov     r13d, 0x0</code></pre><p>I couldn’t figure out what these instructions are doing, since r12-r15 aren’t actually used in this function. It could just be obfuscation by the author.</p><p>What looks like some more obfuscation immediately follows, this time accessed and written to.</p><pre><code class=\"language-x86asm\">mov     eax, dword [rbp-0x5c {input_length}]cdqe    lea     rdx, [rax*8] // 0x30mov     eax, 0x10sub     rax, 0x1add     rax, rdxmov     esi, 0x10mov     edx, 0x0div     rsiimul    rax, rax, 0x10sub     rsp, raxmov     rax, rspadd     rax, 0x7shr     rax, 0x3shl     rax, 0x3mov     qword [rbp-0x40 {seed_data_ptr}], raxmov     rax, qword [rbp-0x40 {seed_data_ptr}]mov     qword [rax], 0x1mov     dword [rbp-0x60 {counter}], 0x1</code></pre><p>Ultimately the stack pointer is subtracted by 0x30, then 7 is added to it. Finally two writes: this stack address is saved into a pointer and a one is placed there (at RAX). A variable later used as a counter (RBP-0x60) is also set to one.</p><h2 id=\"first-loop\">First Loop</h2><p>In the first loop, we can see why.</p><p><img src=\"/assets/img/firstloop.png\" alt=\"array[n] = array[n-1] times 0x83 modulo 0x3b9aca09\" /></p><p>First, the counter is loaded, and then subtracted by one to load into EDX - this is used to calculate an offset from the pointer in the previous block. It is a 64 bit integer, so this is used as an offset from the pointer. On the first iteration, counter = 1, so this is the first (0th) element in the array.</p><p>Next, that value is multiplied by 0x83, and then the remainder modulo 0x3b9aca09 is taken. Finally this is saved at the index marked by counter. In short, the loop is basically this:</p><p><strong>array[n] = array[n-1] * 0x83 % 0x3b9aca09</strong></p><p>You can do the math yourself, or just verify this in the debugger:</p><p><img src=\"/assets/img/seed_data.png\" alt=\"seed data in GDB\" /></p><p>Importantly, these numbers are computed on constants, based on a counter that has to be six - every time you run this program these numbers will be the same. Effectively, it’s just runtime obfuscation of both a pointer (the random bit shifting and saving to <strong>rbp-0x40</strong>) and the data at that pointer. Despite being generated at runtime it’s effectively static data.</p><p>I called this seed data, thinking that this would be relevant in the hash calculation which occurs in the second loop. Knowing that we’re generating this data and seeing a reference to this pointer in the second loop, we can figure out what it is doing.</p><!-- ![array[n] = array[n-1] times 0x83 modulo 0x3b9aca09](/assets/img/seed_data.png) --><h2 id=\"hash-function\">Hash Function</h2><p>First some initialization is performed - After the first loop is finished, the first counter equals six, then the code follows a new block on the right where the hash is initalized with the first byte of the input. The loop only runs through the last five bytes, so this makes sure all of them factor into the hash.</p><p>A second counter is set to 1, since index 0 of the input has already been stored in the hash variable.</p><p><img src=\"/assets/img/hashinit.png\" alt=\"Hash value initalized to first value of input\" /></p><p>The inside of this loop runs five times, and does five main operations.</p><p><img src=\"/assets/img/second_loop.png\" alt=\"Hash loop disassembly\" /></p><ol>  <li>Get the current value of seed data (0x83 to start) into RCX</li>  <li>Get the corresponding byte of input into RAX</li>  <li>Get the remainder of dividing this byte (RAX) by <strong>0x3db9aca09</strong></li>  <li>Multiply this result by the seed value in RCX</li>  <li>Divide this by 0x3db9aca09, and add the remainder to the hash</li></ol><p>This runs five times, eventually ending the loop with a comparison to the correct hash.</p><p>Interestingly, the pre-initialization isn’t really necessary because starting from index zero will produce the same result. The first value % 0x3db9aca09 will equal itself, and multiplying that by the first value of seed data (0x1) has no effect. It’s not immediately clear if this is done by the author or the compiler.</p><p><img src=\"/assets/img/hash_check.png\" alt=\"Hash loop disassembly\" /></p><h2 id=\"keygen\">Keygen</h2><p>Now that we know both the hash and how it is computed, including the seed data/starting state values, we can write brute force any inputs that collide to this value. Since there are only one million possibilities, it can run in under a second.</p><p>Starting off we can define some variables for us, including the seed data just as a list.</p><div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kn\">import</span> <span class=\"nn\">itertools</span><span class=\"n\">HASH</span> <span class=\"o\">=</span> <span class=\"mh\">0x3c0431a5</span> <span class=\"c1\"># hash value of the input to match# valid characters, ASCII 0-9</span><span class=\"n\">VALID</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s\">'0'</span><span class=\"p\">,</span> <span class=\"s\">'1'</span><span class=\"p\">,</span> <span class=\"s\">'2'</span><span class=\"p\">,</span> <span class=\"s\">'3'</span><span class=\"p\">,</span> <span class=\"s\">'4'</span><span class=\"p\">,</span> <span class=\"s\">'5'</span><span class=\"p\">,</span> <span class=\"s\">'6'</span><span class=\"p\">,</span> <span class=\"s\">'7'</span><span class=\"p\">,</span> <span class=\"s\">'8'</span><span class=\"p\">,</span> <span class=\"s\">'9'</span><span class=\"p\">]</span><span class=\"c1\"># generated by the first loop in main, always the same</span><span class=\"n\">seed</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mh\">0x1</span><span class=\"p\">,</span> <span class=\"mh\">0x83</span><span class=\"p\">,</span> <span class=\"mh\">0x4309</span><span class=\"p\">,</span> <span class=\"mh\">0x224d9b</span><span class=\"p\">,</span> <span class=\"mh\">0x118db651</span><span class=\"p\">,</span> <span class=\"mh\">0x228a4e1d</span><span class=\"p\">]</span></code></pre></div></div><p>Translating the steps into python, we can write a short loop to implement the hashing.</p><div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">keyhash</span><span class=\"p\">(</span><span class=\"n\">s</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">):</span>    <span class=\"s\">\"\"\"return the hash of the input\"\"\"</span>    <span class=\"n\">hashvalue</span> <span class=\"o\">=</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"n\">s</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">s</span><span class=\"p\">)):</span>        <span class=\"n\">seedval</span> <span class=\"o\">=</span> <span class=\"n\">seed</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span>        <span class=\"n\">b</span> <span class=\"o\">=</span> <span class=\"nb\">ord</span><span class=\"p\">(</span><span class=\"n\">s</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">])</span> <span class=\"c1\"># byte to use</span>        <span class=\"n\">rem</span> <span class=\"o\">=</span> <span class=\"n\">b</span> <span class=\"o\">%</span> <span class=\"mh\">0x3b9aca09</span>        <span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">rem</span> <span class=\"o\">*</span> <span class=\"n\">seedval</span>        <span class=\"n\">frem</span> <span class=\"o\">=</span> <span class=\"n\">m</span> <span class=\"o\">%</span> <span class=\"mh\">0x3b9aca09</span>        <span class=\"n\">hashvalue</span> <span class=\"o\">+=</span> <span class=\"n\">frem</span>         <span class=\"k\">return</span> <span class=\"n\">hashvalue</span></code></pre></div></div><p>Just like in the challenge binary, it would technically work if the hash was initialized to zero and the loop ran 6 times over the whole input, since the first iteration only multiplies the first value by one.</p><p>We can then use itertools’ cartesian <a href=\"https://docs.python.org/3/library/itertools.html#itertools.product\">product</a> function to brute force all of the keys and check against the hash value.</p><div class=\"language-python highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>    <span class=\"k\">for</span> <span class=\"n\">attempt</span> <span class=\"ow\">in</span> <span class=\"n\">itertools</span><span class=\"p\">.</span><span class=\"n\">product</span><span class=\"p\">(</span><span class=\"n\">VALID</span><span class=\"p\">,</span> <span class=\"n\">repeat</span><span class=\"o\">=</span><span class=\"mi\">6</span><span class=\"p\">):</span>        <span class=\"n\">test</span> <span class=\"o\">=</span> <span class=\"s\">\"\"</span><span class=\"p\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">attempt</span><span class=\"p\">)</span>        <span class=\"n\">check</span> <span class=\"o\">=</span> <span class=\"n\">keyhash</span><span class=\"p\">(</span><span class=\"n\">test</span><span class=\"p\">)</span>        <span class=\"k\">if</span> <span class=\"n\">check</span> <span class=\"o\">==</span> <span class=\"n\">HASH</span><span class=\"p\">:</span> <span class=\"c1\"># 0x3c0431a5</span>            <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">\"Solution:\"</span><span class=\"p\">,</span> <span class=\"n\">test</span><span class=\"p\">,</span> <span class=\"nb\">hex</span><span class=\"p\">(</span><span class=\"n\">check</span><span class=\"p\">))</span>    <span class=\"k\">return</span> <span class=\"mi\">0</span></code></pre></div></div><p>After running this we can finally see:</p><div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ Solution: 231337 0x3c0431a5$ ./crackme 231337Key is valid$ </code></pre></div></div><p>No collisions, and a valid key.</p>",
            "url": "http://mav.codes/2022/05/12/solving-a-crackme-with-binary-ninja",
            
            
            
            
            
            "date_published": "2022-05-12T00:00:00+00:00",
            "date_modified": "2022-05-12T00:00:00+00:00",
            
                "author": 
                "{"twitter"=>nil, "name"=>nil, "avatar"=>nil, "email"=>nil, "url"=>nil}"
                
            
        }
    
    ]
}