Jump to content
Tuts 4 You


  1. Community Links

    1. Terms, Privacy Policy & Frequently Asked Questions   (200,728 visits to this link)

      Very important! Please read before sign up and posting...

  2. Community Discussions

    1. General Discussions and Off Topic

      General and off-topic conversations and discussions here...

    2. Artscene Community

      Share graphics, ASCII, modules, demos, intros, ideas and other works...

    3. Site Bug Reports and Feedback

      Bugs, feedback and ideas regarding this site...

  3. Developers Forums

    1. Programming and Coding

      Programming and coding tips, help and solutions...

    2. Programming Resources

      Share an interesting blog, news page or other resource...

    3. Software Security

      Securing your software against reverse engineering...

  4. Reverse Code Engineering

    1. Challenge of Reverse Engineering

      Try a challenge or contribute your own, any platform or operating system...

    2. Hardware Reverse Engineering

      Reverse engineering of circuitry hardware and firmware...

    3. Network Security

      Discussions on network security, holes, exploits and other issues...

    4. Malware Reverse Engineering

      Debugging, disassembling and documenting interesting malware...

    5. Reverse Engineering Articles

      Share an interesting blog, news page or other RE related site...

    6. Employment and Careers

      Discussions on employment and career paths in the industry...

  5. Community Projects

    1. Scylla Imports Reconstruction

      Development and support forum for the Scylla project...

    2. x64dbg

      An open-source x64/x32 debugger for windows...

    3. Future Community Projects

      Looking for support and interested partners for a future project?

    4. Community Projects Archive

      Old and inactive projects moved to long term support...

  • Member Statistics

    Total Members
    Most Online
    Newest Member
  • Posts

    • Washi
      @Extreme Coders Excellent write-up. Easy to follow and covers everything. Thanks!
    • BlackHat
      This is what I call an actual solution. It explains every step in a proper manner so we can understand each and every action taken by you to solve it.    Thank you.
    • Extreme Coders
      The KeygenMe or more appropriately a CrackMe (since it accepts just a single key) is protected with virtualization based obfuscation. This mini writeup describes a way to obtain the correct key without devirtualization. I - First Steps There are two files - main.py & LicenseChecker.py of which the latter is additionally minified. To improve readability we can run the file through a beautifier like black to get the following code. https://gist.github.com/extremecoders-re/35cb06674676afdcf85bd19d0793d6cc II - Overview The list variable C holds the bytecode for the VM. C=[82,26,95,26,95,26,105, .... snip.... ,571,84,572,84,393,129,3,101,84,103,84,573,76,1,134] The dictionary variable W near the end contains the mappings from the instruction opcode to the corresponding handlers. There are 70 handlers which imply there are the same number of instructions. W = { 10: A0, 179: f, 36: AT, 168: g, # ... snip ... 162: A9, 113: A6, 197: c, 215: AI, } The while loop at the end is the VM fetch-decode-execute loop. while B.a < L(C): try: W[C[B.a]]() except Z as X: A = [X] if not G: raise X P, Ag = G.pop() while F: Ah, Ai, Aj = F and F[-1] or (0, 0, 0) if Ah <= P: break F.pop() B.a = P + Ag B.a += 1 There is a similar loop in one of the handlers AW which implies this must be implementing function calls. III - Simplifying the VM The VM supports 70 instructions but not all of them are used. Hence we can remove the unused handlers to simplify the code. This can be done manually in a trial and error way or we can also automate it by logging which handler  executes and remove the others. Eventually we are left with 18 handlers which after renaming are as follows. W = { 2: h2, 19: h19, 26: h26, 33: h33, 41: h41, 76: h76, 82: h82, 84: h84, 88: h88, 101: h101, 109: h109, 112: h112, 113: h113, 117: h117, 129: h129, 131: h131, 134: h134, 139: h139, } Full simplified code: https://gist.github.com/extremecoders-re/8962f5faefcd714ce5336461fe670c06 IV - Tracing the VMCALL instruction With 18 handlers left we can now trace the VM. An important thing to note is the obfuscator must have a way to call non-obfuscated external functions such as those from the standard library. If we log the external function it calls, the logic of the crackme would be clear. The instruction with opcode 76 implements the VMCALL instruction. def h76(): vmctx.pc += 1 E = G.copy() D = bc[vmctx.pc] F = A.pop() if D & 1 else () H = A.pop() if D & 2 else {} I = A.pop()(*(F), **H) J = G.copy() E == J and A.append(I) We can introduce a logging statement just before the call as shown. below. def h76(): vmctx.pc += 1 E = G.copy() D = bc[vmctx.pc] F = A.pop() if D & 1 else () H = A.pop() if D & 2 else {} # Logging the external function name and arguments print(A[-1].__name__, F, H) I = A.pop()(*(F), **H) J = G.copy() E == J and A.append(I) V - Retrieving the correct key Running with the serial and the VMCALL logging in place verify("ABCDE-FGHIJ-KLMNO-PQRST-UVWXY") we get a trace, of which the important parts are shown below. getitem (['ABCDE', 'FGHIJ', 'KLMNO', 'PQRST', 'UVWXY'], 0) {} getattr ('ABCDE', 'encode') {} encode () {} getattr (<module 'hashlib' from '/usr/lib/python3.10/hashlib.py'>, 'md5') {} openssl_md5 (b'ABCDE',) {} getattr (<md5 _hashlib.HASH object @ 0x7f335f0850f0>, 'digest') {} digest () {} list ((253, 101, 190, 39, 10, 139, 237, 181, 248, 22, 251, 138, 86, 113, 116, 52),) {} bytes ([253, 101, 190, 39, 10, 139, 237, 181, 248, 22, 251, 138, 86, 113, 116, 52],) {} eq (b'.\xcd\xde9Y\x05\x1d\x91?a\xb1Ey\xea\x13m', b"\xfde\xbe'\n\x8b\xed\xb5\xf8\x16\xfb\x8aVqt4") {} not_ (False,) {} It calculates the md5 of the first word -> openssl_md5("ABCDE") which is then compared to b"\xfde\xbe'\n\x8b\xed\xb5\xf8\x16\xfb\x8aVqt4". This can be converted to hex representation. >>> print(b"\xfde\xbe'\n\x8b\xed\xb5\xf8\x16\xfb\x8aVqt4".hex()) fd65be270a8bedb5f816fb8a56717434 The MD5 hash can be reversed with any online tool such as https://hashes.com/en/decrypt/hash  &  https://crackstation.net/ The first word is thus CONGR. Re-running with the following key we get another trace. verify("CONGR-FGHIJ-KLMNO-PQRST-UVWXY") getitem (['CONGR', 'FGHIJ', 'KLMNO', 'PQRST', 'UVWXY'], 1) {} getitem ('FGHIJ', 1) {} eq ('G', 'T') {} Here we see it taking the second word in the key viz FGHIJ and comparing the second character in the word G with T. Thus the correct character at that place is T. Since it stops comparing further letters as soon as a mismatch is found we can only recover the key character by character. However there is a quicker way. We can override the result of the comparison to true such that all the checks are revealed at once. This can be done by a slight modification to the logging logic. def h76(): vmctx.pc += 1 E = G.copy() D = bc[vmctx.pc] F = A.pop() if D & 1 else () H = A.pop() if D & 2 else {} # Logging the external function name and arguments if A[-1].__name__ == "eq": print(A[-1].__name__, F, H) I = True else: I = A.pop()(*(F), **H) J = G.copy() E == J and A.append(I) Running once more with the same key as last time we get the full trace as below. eq (29, 29) {} eq (5, 5) {} eq (5, 5) {} eq (5, 5) {} eq (5, 5) {} eq (5, 5) {} eq (5, 5) {} eq (b"\xfde\xbe'\n\x8b\xed\xb5\xf8\x16\xfb\x8aVqt4", b"\xfde\xbe'\n\x8b\xed\xb5\xf8\x16\xfb\x8aVqt4") {} eq ('G', 'T') {} eq ('O', 'S') {} eq ('Q', 'O') {} eq ('J', 'A') {} eq ('H', 'U') {} eq ('R', 'H') {} eq ('K', 'T') {} eq ('S', 'F') {} eq ('F', 'A') {} eq ('L', 'I') {} eq ('T', 'A') {} eq ('M', 'O') {} eq ('I', 'L') {} eq ('N', 'N') {} eq ('P', 'Q') {} eq ('UYXWV', 'BHZQB') {} From the equality checks we can retrieve the 2nd, 3rd and 4th words in the key. The 1st word has already been retrieved before from the MD5 reversing. CONGR-ATULA-TIONS-QOHFA-UVWXY The fifth word is however checked in a different way. The fifth word in the entered key was UVWXY. However it is checking UYXWV with BHZQB. U -> B Y -> H X -> Z W -> Q V -> B UYXWV is a permutation of the original letters UVWXY. Thus we can simply undo the above mapping in the proper order to get the correct word as shown below. U -> B V -> B W -> Q X -> Z Y -> H The correct last word is BBQZH and thus the complete key: CONGR-ATULA-TIONS-QOHFA-BBQZH
    • whoknows
    • windowbase
      Very Good. I forgot about my submit file, for a while.  Really you did a good job. thank you for your solution. If you can write a tutorial for us. It'd be great for us. thanks again. regards. sean.
  • Popular Contributors

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
      TRISTAN Pro
      TRISTAN Pro
  • Files

  • File Comments

  • Create New...