As rebound to the previous crackme which had in me complete intellectual disarray, I will be doing the crackme here, rated at difficulty 1, if I’m not able to finish this then the RE gods shan’t have mercy on me.

   0x0000000008001226 <+0>:     push   %rbp
   0x0000000008001227 <+1>:     mov    %rsp,%rbp
   0x000000000800122a <+4>:     sub    $0x10,%rsp
   0x000000000800122e <+8>:     mov    %edi,-0x4(%rbp)
   0x0000000008001231 <+11>:    mov    %rsi,-0x10(%rbp)
   0x0000000008001235 <+15>:    cmpl   $0x2,-0x4(%rbp)
   0x0000000008001239 <+19>:    je     0x800124a <main+36>
   0x000000000800123b <+21>:    mov    -0x10(%rbp),%rax
   0x000000000800123f <+25>:    mov    (%rax),%rax
   0x0000000008001242 <+28>:    mov    %rax,%rdi
   0x0000000008001245 <+31>:    callq  0x8001169 <usage>
   0x000000000800124a <+36>:    mov    -0x10(%rbp),%rax
   0x000000000800124e <+40>:    add    $0x8,%rax
   0x0000000008001252 <+44>:    mov    (%rax),%rax
   0x0000000008001255 <+47>:    mov    %rax,%rdi
   0x0000000008001258 <+50>:    callq  0x8001197 <checkSerial>
   0x000000000800125d <+55>:    test   %eax,%eax
   0x000000000800125f <+57>:    jne    0x8001274 <main+78>
   0x0000000008001261 <+59>:    lea    0xda9(%rip),%rdi        # 0x8002011
   0x0000000008001268 <+66>:    callq  0x8001030 <puts@plt>
   0x000000000800126d <+71>:    mov    $0x0,%eax
   0x0000000008001272 <+76>:    jmp    0x8001285 <main+95>
   0x0000000008001274 <+78>:    lea    0xda2(%rip),%rdi        # 0x800201d
   0x000000000800127b <+85>:    callq  0x8001030 <puts@plt>
   0x0000000008001280 <+90>:    mov    $0xffffffff,%eax
   0x0000000008001285 <+95>:    leaveq
   0x0000000008001286 <+96>:    retq

Looks as if it weren’t optimized at all during compilation due to the standard push %rbp; mov %rsp,%rbp; ...; leaveq; retq instructions, and the binary doesn’t seem stripped at all, due to the names of the functions still being there, this should be relatively easy.

   0x0000000008001226 <+0>:     push   %rbp
   0x0000000008001227 <+1>:     mov    %rsp,%rbp
   0x000000000800122a <+4>:     sub    $0x10,%rsp
   0x000000000800122e <+8>:     mov    %edi,-0x4(%rbp)
   0x0000000008001231 <+11>:    mov    %rsi,-0x10(%rbp)
   0x0000000008001235 <+15>:    cmpl   $0x2,-0x4(%rbp)
   0x0000000008001239 <+19>:    je     0x800124a <main+36>
   0x000000000800123b <+21>:    mov    -0x10(%rbp),%rax
   0x000000000800123f <+25>:    mov    (%rax),%rax
   0x0000000008001242 <+28>:    mov    %rax,%rdi
   0x0000000008001245 <+31>:    callq  0x8001169 <usage>

-0x4(%rbp) = argc and -0x10(%rbp) = agv, if two arguments aren't passed then usage (argv[0]);`

   0x0000000008001169 <+0>:     push   %rbp
   0x000000000800116a <+1>:     mov    %rsp,%rbp
   0x000000000800116d <+4>:     sub    $0x10,%rsp
   0x0000000008001171 <+8>:     mov    %rdi,-0x8(%rbp)
   0x0000000008001175 <+12>:    mov    -0x8(%rbp),%rax
   0x0000000008001179 <+16>:    mov    %rax,%rsi
   0x000000000800117c <+19>:    lea    0xe81(%rip),%rdi        # "%s [SERIAL]\n"
   0x0000000008001183 <+26>:    mov    $0x0,%eax
   0x0000000008001188 <+31>:    callq  0x8001050 <printf@plt>
   0x000000000800118d <+36>:    mov    $0xffffffff,%edi
   0x0000000008001192 <+41>:    callq  0x8001060 <exit@plt>

Makes the C as follows:

void
usage (const char *filename)
{
  printf ("%s [SERIAL]\n", filename);
  exit (-1);
}

int
main (int argc, char **argv)
{
  if (argc != 2)
    {
      usage (argv[0]);
    }
  /* <...> */
}

Afterwards:

   0x000000000800124a <+36>:    mov    -0x10(%rbp),%rax
   0x000000000800124e <+40>:    add    $0x8,%rax
   0x0000000008001252 <+44>:    mov    (%rax),%rax
   0x0000000008001255 <+47>:    mov    %rax,%rdi
   0x0000000008001258 <+50>:    callq  0x8001197 <checkSerial>
   0x000000000800125d <+55>:    test   %eax,%eax
   0x000000000800125f <+57>:    jne    0x8001274 <main+78>
   0x0000000008001261 <+59>:    lea    0xda9(%rip),%rdi        # "Good Serial"
   0x0000000008001268 <+66>:    callq  0x8001030 <puts@plt>
   0x000000000800126d <+71>:    mov    $0x0,%eax
   0x0000000008001272 <+76>:    jmp    0x8001285 <main+95>
   0x0000000008001274 <+78>:    lea    0xda2(%rip),%rdi        # "Bad Serial"
   0x000000000800127b <+85>:    callq  0x8001030 <puts@plt>
   0x0000000008001280 <+90>:    mov    $0xffffffff,%eax
   0x0000000008001285 <+95>:    leaveq
   0x0000000008001286 <+96>:    retq

Translates to:

void
usage (const char *filename)
{
  printf ("%s [SERIAL]\n", filename);
  exit (-1);
}

int
main (int argc, char **argv)
{
  if (argc != 2)
    {
      usage (argv[0]);
    }
  bool result = checkSerial (argv[1]);
  if (result)
    {
      puts ("Good Serial");
      return 0;
    }
  puts ("Bad Serial");
  return -1;
}

Then, the more interesting checkSerial function is as follows:

   0x0000000008001197 <+0>:     push   %rbp                                        
   0x0000000008001198 <+1>:     mov    %rsp,%rbp                                   
   0x000000000800119b <+4>:     push   %rbx                                        
   0x000000000800119c <+5>:     sub    $0x28,%rsp                                  
   0x00000000080011a0 <+9>:     mov    %rdi,-0x28(%rbp)                            
   0x00000000080011a4 <+13>:    mov    -0x28(%rbp),%rax                            
   0x00000000080011a8 <+17>:    mov    %rax,%rdi                                   
   0x00000000080011ab <+20>:    callq  0x8001040 <strlen@plt>                      
   0x00000000080011b0 <+25>:    cmp    $0x10,%rax                                  
   0x00000000080011b4 <+29>:    je     0x80011bd <checkSerial+38>                  
   0x00000000080011b6 <+31>:    mov    $0xffffffff,%eax                            
   0x00000000080011bb <+36>:    jmp    0x800121f <checkSerial+136>                 
   0x00000000080011bd <+38>:    movl   $0x0,-0x14(%rbp)                            
   0x00000000080011c4 <+45>:    jmp    0x8001203 <checkSerial+108>                 
   0x00000000080011c6 <+47>:    mov    -0x14(%rbp),%eax                            
   0x00000000080011c9 <+50>:    movslq %eax,%rdx                                   
   0x00000000080011cc <+53>:    mov    -0x28(%rbp),%rax                            
   0x00000000080011d0 <+57>:    add    %rdx,%rax                                   
   0x00000000080011d3 <+60>:    movzbl (%rax),%eax                                 
   0x00000000080011d6 <+63>:    movsbl %al,%edx                                    
   0x00000000080011d9 <+66>:    mov    -0x14(%rbp),%eax                            
   0x00000000080011dc <+69>:    cltq                                               
   0x00000000080011de <+71>:    lea    0x1(%rax),%rcx                              
   0x00000000080011e2 <+75>:    mov    -0x28(%rbp),%rax                            
   0x00000000080011e6 <+79>:    add    %rcx,%rax                                   
   0x00000000080011e9 <+82>:    movzbl (%rax),%eax                                 
   0x00000000080011ec <+85>:    movsbl %al,%eax                                    
   0x00000000080011ef <+88>:    sub    %eax,%edx                                   
   0x00000000080011f1 <+90>:    mov    %edx,%eax                                   
   0x00000000080011f3 <+92>:    cmp    $0xffffffff,%eax                            
   0x00000000080011f6 <+95>:    je     0x80011ff <checkSerial+104>                 
   0x00000000080011f8 <+97>:    mov    $0xffffffff,%eax                            
   0x00000000080011fd <+102>:   jmp    0x800121f <checkSerial+136>                 
   0x00000000080011ff <+104>:   addl   $0x2,-0x14(%rbp)                            
   0x0000000008001203 <+108>:   mov    -0x14(%rbp),%eax                            
   0x0000000008001206 <+111>:   movslq %eax,%rbx                                   
   0x0000000008001209 <+114>:   mov    -0x28(%rbp),%rax                            
   0x000000000800120d <+118>:   mov    %rax,%rdi                                   
   0x0000000008001210 <+121>:   callq  0x8001040 <strlen@plt>                                                 
   0x0000000008001215 <+126>:   cmp    %rax,%rbx                                   
   0x0000000008001218 <+129>:   jb     0x80011c6 <checkSerial+47>                  
   0x000000000800121a <+131>:   mov    $0x0,%eax                                   
   0x000000000800121f <+136>:   add    $0x28,%rsp                                  
   0x0000000008001223 <+140>:   pop    %rbx                                        
   0x0000000008001224 <+141>:   pop    %rbp                                        
   0x0000000008001225 <+142>:   retq                                               

Recall, %rdi = argv[1]:

   0x0000000008001197 <+0>:     push   %rbp                                        
   0x0000000008001198 <+1>:     mov    %rsp,%rbp                                   
   0x000000000800119b <+4>:     push   %rbx                                        
   0x000000000800119c <+5>:     sub    $0x28,%rsp                                  
   0x00000000080011a0 <+9>:     mov    %rdi,-0x28(%rbp)                            
   0x00000000080011a4 <+13>:    mov    -0x28(%rbp),%rax                            
   0x00000000080011a8 <+17>:    mov    %rax,%rdi                                   
   0x00000000080011ab <+20>:    callq  0x8001040 <strlen@plt>                      
   0x00000000080011b0 <+25>:    cmp    $0x10,%rax                                  
   0x00000000080011b4 <+29>:    je     0x80011bd <checkSerial+38>                  
   0x00000000080011b6 <+31>:    mov    $0xffffffff,%eax                            
   0x00000000080011bb <+36>:    jmp    0x800121f <checkSerial+136>  

And so we have:

bool
checkSerial (const char *input)
{
  if (strlen (input) != 0x10)
    {
      return -1;
    }
  /* <...> */
}

Then:

   0x00000000080011bd <+38>:    movl   $0x0,-0x14(%rbp)                            
   0x00000000080011c4 <+45>:    jmp    0x8001203 <checkSerial+108>   
...
   0x0000000008001203 <+108>:   mov    -0x14(%rbp),%eax                            
   0x0000000008001206 <+111>:   movslq %eax,%rbx                                   
   0x0000000008001209 <+114>:   mov    -0x28(%rbp),%rax                            
   0x000000000800120d <+118>:   mov    %rax,%rdi                                   
   0x0000000008001210 <+121>:   callq  0x8001040 <strlen@plt>                                                 
   0x0000000008001215 <+126>:   cmp    %rax,%rbx                                   
   0x0000000008001218 <+129>:   jb     0x80011c6 <checkSerial+47>                  
   0x000000000800121a <+131>:   mov    $0x0,%eax                                   
   0x000000000800121f <+136>:   add    $0x28,%rsp                                  
   0x0000000008001223 <+140>:   pop    %rbx                                        
   0x0000000008001224 <+141>:   pop    %rbp                                        
   0x0000000008001225 <+142>:   retq     

This is indicative of a while-loop, revolving around that %rbx - %rax < 0, i.e. %rbx < %rax, given that %rax is strlen (argv[1]) and %rbx which is 0 to begin with then 0 < 16 (since upon first iteration the serial has to be 16 characters).

   0x00000000080011c6 <+47>:    mov    -0x14(%rbp),%eax                            
   0x00000000080011c9 <+50>:    movslq %eax,%rdx                                   
   0x00000000080011cc <+53>:    mov    -0x28(%rbp),%rax                            
   0x00000000080011d0 <+57>:    add    %rdx,%rax                                   
   0x00000000080011d3 <+60>:    movzbl (%rax),%eax                                 
   0x00000000080011d6 <+63>:    movsbl %al,%edx                                    
   0x00000000080011d9 <+66>:    mov    -0x14(%rbp),%eax                            
   0x00000000080011dc <+69>:    cltq                                               
   0x00000000080011de <+71>:    lea    0x1(%rax),%rcx                              
   0x00000000080011e2 <+75>:    mov    -0x28(%rbp),%rax                            
   0x00000000080011e6 <+79>:    add    %rcx,%rax                                   
   0x00000000080011e9 <+82>:    movzbl (%rax),%eax                                 
   0x00000000080011ec <+85>:    movsbl %al,%eax                                    
   0x00000000080011ef <+88>:    sub    %eax,%edx                                   
   0x00000000080011f1 <+90>:    mov    %edx,%eax                                   
   0x00000000080011f3 <+92>:    cmp    $0xffffffff,%eax                            
   0x00000000080011f6 <+95>:    je     0x80011ff <checkSerial+104>                 
   0x00000000080011f8 <+97>:    mov    $0xffffffff,%eax                            
   0x00000000080011fd <+102>:   jmp    0x800121f <checkSerial+136>                 
   0x00000000080011ff <+104>:   addl   $0x2,-0x14(%rbp)                            
   0x0000000008001203 <+108>:   mov    -0x14(%rbp),%eax                            
   0x0000000008001206 <+111>:   movslq %eax,%rbx    

Note +136 is the return, +108 is the condition.

   0x00000000080011c6 <+47>:    mov    -0x14(%rbp),%eax                            
   0x00000000080011c9 <+50>:    movslq %eax,%rdx                                   
   0x00000000080011cc <+53>:    mov    -0x28(%rbp),%rax                            
   0x00000000080011d0 <+57>:    add    %rdx,%rax                                   
   0x00000000080011d3 <+60>:    movzbl (%rax),%eax                                 
   0x00000000080011d6 <+63>:    movsbl %al,%edx                                    
   0x00000000080011d9 <+66>:    mov    -0x14(%rbp),%eax                            
   0x00000000080011dc <+69>:    cltq   

+57 gets the %rdxth byte of argv[1], so %rax = (argv[1] + %rdx), afterwards having %edx be that certain byte, i.e. %edx = argv[1][%rdx]:

   0x00000000080011de <+71>:    lea    0x1(%rax),%rcx                              
   0x00000000080011e2 <+75>:    mov    -0x28(%rbp),%rax                            
   0x00000000080011e6 <+79>:    add    %rcx,%rax                                   
   0x00000000080011e9 <+82>:    movzbl (%rax),%eax                                 
   0x00000000080011ec <+85>:    movsbl %al,%eax                                    
   0x00000000080011ef <+88>:    sub    %eax,%edx                                   
   0x00000000080011f1 <+90>:    mov    %edx,%eax                                   
   0x00000000080011f3 <+92>:    cmp    $0xffffffff,%eax                            
   0x00000000080011f6 <+95>:    je     0x80011ff <checkSerial+104>                 
   0x00000000080011f8 <+97>:    mov    $0xffffffff,%eax                            
   0x00000000080011fd <+102>:   jmp    0x800121f <checkSerial+136>  
   0x00000000080011ff <+104>:   addl   $0x2,-0x14(%rbp)   

Afterwards, we load %rcx with -0x14(%rbp) + 1, set %rax to argv[1] again, so we have %eax = argv[1][%rcx], afterwards we subtract the two bytes argv[1][k] and argv[1][k+1], compare if the difference between them is -1, if so, rerun the condition, otherwise, exit.

bool
checkSerial (const char *input)
{
  if (strlen (input) != 0x10)
    {
      return -1;
    }
  int acc = 0;
  while (acc < strlen (input))
    {
      int diff = input[acc] - input[acc + 1];
      if (diff != -1)
        {
          return -1;
        }
      acc += 2;
    }
  return 0;
}

By this, we have the solution, we need a string of characters such that a character at some position 2k with ordinal 2k_c must also imply 2(k + 1) has ordinal 2k_c + 1, therefore a simple string such as "abababababababab" or "abcdefghijklmnop' would work:

EDITORIAL NOTE: The positions are of a factor of 2 due to the line acc += 2;

$4.4 DESKTOP-AVEP851@unazed ~ 255
>./SimpleKeyGen abcdefghijklmnop
Good Serial
$4.4 DESKTOP-AVEP851@unazed ~ 0
>./SimpleKeyGen abababababababab
Good Serial

Which it does.

Thanks for reading.