2

I'm currently learning to do some basic reverse engineering of binary files using Cutter. The program i'm struggling on test if the password entered as argument is correct, if not, return an error message. I have some serious gap in assembly and I can't figure out the password on this one. I've worked on it for some times and arrived at a point where i'm stuck..

Here is the decompiled code, the test of the password happend during the while/if iterations so what's before is just to give some contex.

undefined4 main(int param_1,int param_2){
    undefined4 uVar1;
    size_t sVar2;
    undefined4 local_21;
    undefined4 local_1d;
    undefined local_19;
    char *local_18;
    int local_14;
    undefined4 *local_10;

    local_10 = &param_1;
    local_14 = 0;
    if (param_1 == 2) {
          local_21 = 0x776f7264;
          local_1d = 0x70617373;
          local_19 = 0;
          local_18 = *(char **)(param_2 + 4);
          sVar2 = strlen(local_18);
          if (sVar2 < 8) {
                uVar1 = 0xffffffff;
          }
          else {
                while (local_14 < 8) {
                      if ((int)local_18[local_14] + 1 != (int)*(char                   
                          *)((int)&local_21 + local_14)) {
                              puts("Wrong password.");
                              return 0xffffffff;
                      }
                      local_14 = local_14 + 1;
                }
                puts("Access granted.");
                uVar1 = 0;
                }
          }
    else {
          puts("One and only one argument PLS.");
          uVar1 = 0xffffffff;
    }
    return uVar1;
}

UPDATE 1, What I know from my guess and the help of others :

  • The program doesn't return any error message if the password given is less than 8 character. (If it is >=8 it says that the password is incorrect). I do think that the password must be 8 character.

  • The password is probably in hexadecimal. Why do I think that ? the var used during the verification of the password (local_21 = 776f7264 = word) is exactly 8 characters and we do iterate 8 times in the verification.

  • There's some kind of shift involved since we are testing (local_18[local_14] + 1) with local_18 the argument i entered and local_14 the iterator being incremented in the end of the while. From what I've been told that it will shift the password i enter and it need to be the same as (int)*(char *)((int)&local_21 + local_14)) but i can't figure out what is it.

  • So If my though are correct, i need to find a 8 caracter Hexadecimal from which i'll shift the characters (remplace b by a for example) to match what i'm trying to translate " (int)*(char *)((int)&local_21 + local_14)) "

I'm trying to find out if I'm right..

UPDATE 2, Here is a screen of the assembly tree and the while section zoomed in.

I also commented it below but as you can see there's some section where I just can't understand what's happening :

VARS : 
local_21 = 0x776f7264 ; (String) word used in password comparaison
local_1d = 0x70617373 ;(String) pass but unused
local_14 = 0 ;iterator
local_18 = argv[1] (it's the string given as an argument, let's 
           assume i've entered "examples")

- mov edx, dword [local_14] -->  load the value of local_14 into edx 
                                 local_14 = 0

- mov eax, dword[local_18] --> load the function argument into the 
                               register 
                               local_18 = examples


- add eax, edx --> add the value 0 to our password (does it means we 
                   add 0 to the address of our input or directly to 
                   the input ?)

- movzx eax, byte[eax] --> get the first character in eax (is he 
                           taking the hexa character 7 ?

- movsx eax, al --> ?

- lea ecx, [eax + 1] --> load the address of [eax+1] into eax (don't 
                         know what is in eax+1..)

- lea edx, [local_21] --> load the address of local_21 in edx
                          it is 0x776f7264 so what does it stock ? Do 
                          I considerer this as a value or as an 
                          address?

- mov eax, dword[local_14] --> load the value of local_14 (0) into 
                             eax, so 0x0 ?

- add eax, edx -> we add local_14 (0) to eax, so do we have 0x776f7264

- movzx eax, byte[eax] --> exact same thing as before.

- movsx eax, al --> same as before

- cmp ecx, eax --> we compare ecx et eax (eax=?, ecx = [eax+1] = ?)

- add dword [local_14], 1 --> we add 1 to (local_14), it became 1 (our 
                            iterator)

- cmp dword [local-14], 7 --> we compare our iterator with with 7, if 
                              it is lower we continue 

- we start again from the start 

I have trouble understand if 0x776f7264 is actually an address or just the value in eax. So when i add 1, what is actually happend (2,3 etc..) ? Do i had this directly to the hexa or do I consider adding it to a character ? Like 77 = w so i add 1 to w and it gives me x

I'm really sorry if i have poorly explained my problem and will do my best to answer any questions regarding my post.

Thanks a lot and have a nice day !

1
  • 1
    You are almost there with your analysis. I think if you would rename some of the vars and change the types it would be more clear. Maybe support yourself with debugging, too? Apr 7, 2020 at 10:55

1 Answer 1

2

Some of your observations are correct and some are not.

Let's analyze that:

  • local_14 is indeed a loop iterator, so the while loop is in fact a for loop that runs 8 iterations. You can try renaming that variable to i for better clarity.
  • local_18 is the user input, which like you observed, should be in the length of 8; otherwise the check fails.
  • The decompiler cannot infer what local_21 is and shows it as an integer. However, we can see that local_18 is compared to it (local_14 used as the index to that buffer), so it might be a char buffer after all. Additionally, we know that the comparison of local_18 and local_21 is 8 bytes long - so what is going on? Decompilation can be misleading sometime, and this is an example for that: note that local_21 and local_1d are consecutive on the stack (which I remind you, grows backwards) so they are in fact a single char buffer in a size of 8. The compiler initializes them both as integers, because this is the optimized way to do so. Note that 0x776f7264 and 0x70617373 are ASCII strings, an observation that comes with the experience in reverse engineering. This is just a simple 'memcmp' in a size of 8; it is hard to see that because of the excessive casting there.

BTW, the password is not hexadecimal, this is just how data is stored in memory. The interpretation of the values are context-depended.

Hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.