Home Unmasking Secrets: Deciphering Encrypted Passwords through Reverse Engineering

Unmasking Secrets: Deciphering Encrypted Passwords through Reverse Engineering

I’ve been working through some online hacking labs lately to sharpen my skills. While working through the lab I encounter a configuration file that contained a user account and what seemed to be an encrypted password. The file that I found contained the following information:


I made note of it during the lab and figured that it may come in handy later. I then found a executable that named SecurePass.exe. Thats interesting because the tags in the configuration that I noted earlier seemed to match this executable name. I download the executable and threw it on my development and reverse engineering virtual machine and executed it.

My assumption was right this executable was probably used to generate the password I saw earlier. So first lets run this over to my REMnux machine and run peframe against it to see if we can find anything interesting. Oh thats interesting, we can see that the use of RijnDael or AES is used. in the portable executable.

Now lets throw it in x64dbg and see what we can find. I began by running xAnalyzer to help aid me and catch all the references to intermodular calls and help me easily debug the executable.

After xAnalyzer completed I began stepping through the executable and noticed that the password I initially supplied (test) was being stored in RBP not only that, but I noticed a few other strings that were referenced at this point such as:

  • %02x
  • SP%s%s\n
  • Usage information

Well I knew that %02x is related to C string formatting and printing out the data in hex notation. As for SP%s%s\n it was also related C string formatting and shows that a string starts with SP and has two string that come right after that. This is similar to what we saw in the password output and the config file password. Another point to note is that the value after the SP is 64 characters long. I continue to step through the program a bit more and noticed that the password that is was initially supplied is now moved to RCX register. Since this is x64 that means that the following registers are used before calling a sub routine:

  • RDI: Used for the first integer parameter.
  • RSI: Used for the second integer parameter.
  • RDX: Used for the third integer parameter.
  • RCX: Used for the fourth integer parameter.
  • R8 and R9: Used for the fifth and sixth integer parameters, if necessary.

Which means that the user supplied password is now being passed to this function. If RCX is being used that means we can also make note of RDI, RSI, and RDX. The values stored in these registers don’t really mean much to me now, but could be relevant. Maybe RDX is storing the length of the password (4)? I’m not sure… Lets step into this program and see what is going on.

Once inside this function I continue to step over instructions and noticed this interesting loop. It essentially loops through the supplied password and XOR’s it with 42 which is A in base 10 notation. This turns test to 6'16. The next loop we encounter essentially reverses the XOR’d password. This turns the password to 61'6 I continued to step over the calls and noticed that another sub routine is called. I stepped over this sub routine and noticed that R9 returned with a pointer to a memory location. So I followed this in the memory dump and noticed that a 32 bit value is stored.

At this point I’m not sure the point of this, but 32 is a power of 2 and half of the original encrypted password length (64). This maybe a part half of of the password or a salt?


I noticed a few other sub routines being called and just stepped over them. I noticed that they returned a padded version of the XOR’d and reversed password. This value returned also happens to be 32 bits! Coincidence? I Think Not!

So we know that our input password goes through the following order of operations:

  • XOR’d with A (42)
  • Reversed
  • Padded to reach a length of 32 bits

I went ahead and went through the next loop and noticed that 6 is turned to Q, decremented then returns another byte. Once it got to the 4th character (6) the value that was returned it wasn’t Q. Hmm something is happening here… I’m not sure yet, but I will figure it out.

Right after the inner loop ends we can see that RBX is moved into RCX and there is an instruction call right before the sub routine is being called. What is this stored in RCX? So I followed it in the memory dump and noticed that the first 4 bytes matched what I saw being returned earlier. Which is a 32 bit value.

Now I’m curious what is use of the data stored in RCX. So lets step into the sub routine and see whats going on.

We can initially see normal functionality of a sub routine which is the registers being pushed to the call stack. Right after the registers are pushed to the stack we can see that RDX is moved to R15. I followed this in the dump, but didn’t recognize the value stored at the address. For awhile I couldn’t figure out the relevancy of this value. So I ran the executable several times and noticed that the value was static and didn’t change. So it wasn’t being calculated it. I noticed in the upcoming loop that R15+RCX is looped through. This value in R15 is being used for something. It must be a static key!

This must be the AES encryption I identified earlier. Well I know that AES 256 is pretty common and uses a key and IV. The length has to be a power of 2. The static key we found happens to be 32 bits which is in fact a power of 2. I also knew that its technically best practice to have a unique IV when encrypting. I took the password that was identified in the config and split it into two 32 bit parts. Either the first part of the password is the IV or the second part is the IV. So Ive narrowed it down:

Static Key = 8623050922AB890BBD2F79886CD6809F 

IV = 81274145f4a5857b839ee7b500f1d66e OR 8a044d12211781b515e7bae67bb7abce

I now have a 50/50 shot at guessing which is the IV since both of these values are uniquely generated. I plugged this into CyberChef and figured out the following:


The password for svc_me must be jYEp9bq32KFLVL!. I tried this out later in the lab I was working on and it was in fact the password. A small win, but big victory for me.

Happy Hacking :)


This post is licensed under CC BY 4.0 by the author.