DEV Community

ddupard
ddupard

Posted on

CrackMe Level 6: part 2

1. Introduction

In the previous article, we began studying a level 6 CrackMe and quickly reached the Serial verification routine based on the Name.

Here is this routine below:

   0x401510:   pusha                         ; Save all general-purpose registers

   ; -------------------------------------------------------------------------
   ; PHASE 1: BASE64 DECODING AND SIZE CHECK
   ; -------------------------------------------------------------------------
   0x401511:   mov    ebx,DWORD PTR [esp+0x2c]; ebx = Pointer to Serial (passed as parameter)
   0x401515:   mov    esi,0x404200           ; esi = Destination buffer for decoded Serial
   0x40151a:   push   ebx                    ; Argument 2: Serial string
   0x40151b:   push   esi                    ; Argument 1: Output buffer
   0x40151c:   call   0x401633               ; CALL: Custom Base64 decoder
   0x401521:   cmp    eax,0x10               ; Is the decoded buffer exactly 16 bytes (128 bits)?
   0x401524:   jne    0x40162f               ; No -> Direct failure (Jump to failure)

   ; -------------------------------------------------------------------------
   ; PHASE 2: CHECK AND PREPARATION OF 64-BIT INTEGERS (S1 AND S2)
   ; -------------------------------------------------------------------------
   0x40152a:   lea    edi,[esi+0x10]         ; edi = Pointer to second memory block (0x404210)

   ; Verification of the First 64-bit Number: S1 = [esi] (0x404200)
   0x40152d:   mov    eax,DWORD PTR [esi]    ; eax = Low 32 bits of S1
   0x40152f:   mov    edx,DWORD PTR [esi+0x4]; edx = High 32 bits of S1
   0x401532:   test   edx,edx                ; Is S1 zero?
   0x401534:   jne    0x40153e
   0x401536:   test   eax,eax
   0x401538:   je     0x40162f               ; If S1 == 0 -> Failure

   ; Comparison of S1 with Modulus M (stored at 0x40403c)
   0x40153e:   sub    eax,DWORD PTR ds:0x40403c ; S1 - Modulus (low part)
   0x401544:   sbb    edx,DWORD PTR ds:0x404040 ; S1 - Modulus (high part with borrow)
   0x40154a:   jae    0x40162f               ; If S1 >= Modulus -> Failure (S1 must be < M)

   ; Copy and Verification of the Second 64-bit Number: S2 = [esi+0x8] (0x404208)
   0x401550:   mov    eax,DWORD PTR [esi+0x8]; eax = Low 32 bits of S2
   0x401553:   mov    edx,DWORD PTR [esi+0xc]; edx = High 32 bits of S2
   0x401556:   mov    DWORD PTR [edi],eax    ; Copy S2 to edi
   0x401558:   mov    DWORD PTR [edi+0x4],edx
   0x40155b:   test   edx,edx                ; Is S2 zero?
   0x40155d:   jne    0x401567
   0x40155f:   test   eax,eax
   0x401561:   je     0x40162f               ; If S2 == 0 -> Failure

   ; Comparison of S2 with Modulus M
   0x401567:   sub    eax,DWORD PTR ds:0x40403c
   0x40156d:   sbb    edx,DWORD PTR ds:0x404040
   0x401573:   jae    0x40162f               ; If S2 >= Modulus -> Failure

   ; Initialize structures for big integer calculations
   0x401579:   mov    ebx,0x4041e0           ; ebx = Intermediate result structure
   0x40157e:   and    DWORD PTR [esi+0x8],0x0; Zero out structure ends (Padding)
   0x401582:   and    DWORD PTR [edi+0x8],0x0

   ; -------------------------------------------------------------------------
   ; PHASE 3: CRYPTOGRAPHIC CALCULATIONS (MODULAR EXPONENTIATION)
   ; -------------------------------------------------------------------------
   ; Preparation for first modular calculation: C1 = (S2 ^ e) mod M
   0x401586:   push   0x404220               ; Destination for result
   0x40158b:   push   0x404020               ; Pointer to Public Exponent (e)
   0x401590:   push   edi                    ; Operand: S2
   0x401591:   call   0x4020e0               ; CALL: BigInt Math (Modular Exponentiation)

   ; Preparation for second modular calculation: C2 = (S1 ^ e) mod M
   0x401596:   push   ebx                    ; Destination
   0x401597:   push   0x404000               ; Pointer to Modulus / Parameters
   0x40159c:   push   esi                    ; Operand: S1
   0x40159d:   call   0x4020e0               ; CALL: BigInt Math (Modular Exponentiation)

   ; Combine intermediate results
   0x4015a2:   push   ebx
   0x4015a3:   push   0x404220
   0x4015a8:   call   0x401e30               ; CALL: Multiplication / Modular transformation
   0x4015ad:   mov    eax,DWORD PTR [ebx]
   0x4015af:   test   eax,eax                ; Check result validity
   0x4015b1:   je     0x40162f

   0x4015b3:   mov    edi,0x404240
   0x4015b8:   push   edi
   0x4015b9:   push   ebx
   0x4015ba:   call   0x402087               ; CALL: BigInt Normalization / Reduction
   0x4015bf:   push   0x404250
   0x4015c4:   push   edi
   0x4015c5:   call   0x4021cd               ; CALL: Extract final 64-bit value

   ; Modular adjustment of S1
   0x4015ca:   mov    eax,DWORD PTR [esi]
   0x4015cc:   mov    edx,DWORD PTR [esi+0x4]
   0x4015cf:   sub    eax,DWORD PTR ds:0x404250
   0x4015d5:   sbb    edx,DWORD PTR ds:0x404254
   0x4015db:   jae    0x4015e9
   0x4015dd:   add    eax,DWORD PTR ds:0x40403c
   0x4015e3:   adc    edx,DWORD PTR ds:0x404040

   ; -------------------------------------------------------------------------
   ; PHASE 4: NAME HASHING AND FINAL COMBINATION (CHECK)
   ; -------------------------------------------------------------------------
   0x4015e9:   mov    esi,DWORD PTR [esp+0x24]; esi = Length of Name
   0x4015ed:   mov    ecx,DWORD PTR [esp+0x28]; ecx = Pointer to Name string
   0x4015f1:   push   esi
   0x4015f2:   push   ecx
   0x4015f3:   push   edi                     ; Buffer receiving the Hash
   0x4015f4:   call   0x401700                ; CALL: Name Hashing Function (H_Name)

   ; Extract calculated footprint from Name
   0x4015f9:   mov    ebx,DWORD PTR [edi]     ; ebx = Hash_Name (low 32 bits)
   0x4015fb:   mov    ebp,DWORD PTR [edi+0x4] ; ebp = Hash_Name (high 32 bits)
   0x4015fe:   xor    ebx,DWORD PTR [edi+0x8] ; XOR masking with derived components
   0x401601:   xor    ebp,DWORD PTR [edi+0xc]

   ; Adjustment / Reduction of the final mask with the Modulus
   0x401604:   sub    ebx,DWORD PTR ds:0x40403c
   0x40160a:   sbb    ebp,DWORD PTR ds:0x404040
   0x401610:   jae    0x40161e
   0x401612:   add    ebx,DWORD PTR ds:0x40403c
   0x401618:   adc    ebp,DWORD PTR ds:0x404040

   ; FINAL CHECK: Comparison (Calculated Result XOR Name Mask) == 0 ?
   0x40161e:   xor    eax,ebx                 ; Difference on low part
   0x401620:   xor    edx,ebp                 ; Difference on high part
   0x401622:   or     eax,edx                 ; Combine both parts (EAX = 0 if exact match)
   0x401624:   jne    0x40162f                ; If EAX != 0 -> Bad Serial!

   ; -------------------------------------------------------------------------
   ; PHASE 5: SUCCESS OR FAILURE
   ; -------------------------------------------------------------------------
   0x401626:   inc    eax                     ; EAX = 1 (Success)
   0x401627:   mov    DWORD PTR [esp+0x1c],eax; Save return code in stack frame
   0x40162b:   popa                           ; Restore registers
   0x40162c:   ret    0xc                     ; Clean up stack and return (Validated)

   0x40162f:   xor    eax,eax                 ; EAX = 0 (Failure)
   0x401631:   jmp    0x401627                ; Exit to failure

Enter fullscreen mode Exit fullscreen mode

While the first part of the disassembly was fairly ordinary, this one confirms why this crackme is rated level 6.


2. Algorithm Analysis

A detailed analysis of the code reveals a structured and advanced algorithmic architecture:

A. Custom / Base64 Decoding (0x00401633)

The secondary function called at the very beginning (0x0040151c: call 0x401633) is a custom implementation of a Base64 decoder.

  • The Custom Alphabet (0x404048): The code iterates through an alphabet stored at address 0x404048 (mov bl, 0x3f \rightarrow from 63 down to 0) to map the characters.
  • Padding Handling (0x00401687 and 0x004016a4): It looks for the = character (0x3D) and increments dh to manage the final padding.
  • Byte Reconstitution (0x004016c3 - 0x004016e0): Packets of 4 6-bit characters (24 bits) are reassembled and extracted as 3 binary bytes using rotations rol eax, 0x10, 0x8.
  • Size Verification (0x00401521): The decoded result must be exactly 16 bytes (0x10, or 128 bits). This is why the entered Serial had to consist of 24 Base64 characters ( 24×6=144 bits24 \times 6 = 144 \text{ bits} , or 18 raw bytes with padding).

B. Large-Scale Arithmetic Validation (Asymmetric Cryptography / RSA)

Once the 16 bytes are split into two 64-bit blocks ([esi] and [esi+0x8]), the program switches to a big-integer arithmetic library:

  • Bounds Checks (0x0040153e and 0x00401567): The 64-bit integers are compared (via sub / sbb / jae) against a modulus or maximum value stored at 0x40403c.
  • Modular Operations (0x00401591 and 0x0040159d: call 0x4020e0): These functions serve as wrappers for modular exponentiation (RSA or Diffie-Hellman type) or elliptic curve calculations.
  • Name-related Comparison (0x004015f4: call 0x401700): The username is hashed or derived to serve as a comparison key/mask (xor ebx, [edi+0x8]).

C. Summary

The mechanism boils down to three main phases:

  1. Phase 1 (Format): Conversion of the 24-character Serial (Base64) into a 16-byte (128-bit) binary buffer.
  2. Phase 2 (Mathematics): Processing the 128 bits as two 64-bit integers subjected to modular exponentiation equations.
  3. Phase 3 (Name/Key Binding): A fingerprint derived from the Name is injected via a XOR mask to verify final equality (or eax, edx \rightarrow jne 0x40162f / failure).

3. How to Break This CrackMe?

To break a CrackMe based on modular arithmetic (RSA or 64-bit modular exponentiation type), two main approaches are available: mathematical inversion (Keygenning) or binary modification (Patching). We covered binary modification in the previous article; in this article, we will look at Keygenning.

A. Mathematical Engine of the CrackMe

The core of the verification follows this logic:

  1. Extraction: The Serial (24 Base64 chars) is decoded into a 128-bit block divided into two 64-bit integers: S1S_1 and S2S_2 .
  2. Modular Computation: The program executes a modular exponentiation:
C=(S1e(modM))orC=ModularExponentiation(S1,S2,M) C = (S_1^e \pmod M) \quad \text{or} \quad C = \text{ModularExponentiation}(S_1, S_2, M)
  1. Binding with the Name: The result CC is combined via a XOR mask with a fingerprint of the Name HNameH_{\text{Name}} :
CHName=?S2 C \oplus H_{\text{Name}} \stackrel{?}{=} S_2
  1. Validation: At address 0x00401622, the register EAX holds the result of the equality check. If EAX = 0, the program jumps to failure (jne 0x40162f). If there is equality, EAX is incremented to 1 (inc eax), validating the serial.

B. Keygenning (Mathematical Resolution)

This type of function can be inverted to generate a valid Serial for any Name, provided you extract the cryptographic parameters from the binary.

Unlike a pure hash (such as MD5 or SHA-256) which destroys information, the core of this function relies on asymmetric cryptography (modular exponentiation / RSA type). The mathematical relationship is designed to be a trapdoor function: difficult to invert without the private key, but perfectly reversible if one manages to break the modulus MM .

a. Why and how is this function inverted?

The verification process executes the following public operation:

C=(S1e)(modM) C = (S_1^e) \pmod M

To build a key generator (Keygen) for a given Name, the process involves inverting this equation:

  1. Computing the Name Hash: You pass the Name through the hashing function 0x00401700 to obtain the fingerprint HNameH_{\text{Name}} .
  2. Reconstructing the Target: By analyzing the XOR operations and modular adjustments in Phase 4, you deduce the target value CC that the calculation must yield.
  3. Calculating the Private Key dd :
  4. You retrieve the modulus MM (at address 0x40403c) and the public exponent ee (at address 0x404020).
  5. Since MM is a 64-bit integer (i.e., 8 bytes, visible with the 32-bit sub/sbb instructions), its factorization into two prime numbers pp and qq is instantaneous on a modern computer (using a tool like PARI/GP, SageMath, or Factordb).
  6. Once pp and qq are known, you calculate Euler's totient function
    ϕ(M)=(p1)(q1)\phi(M) = (p - 1)(q - 1)
    , and then the private exponent dd such that:
de1(modϕ(M)) d \equiv e^{-1} \pmod{\phi(M)}
  1. Calculating S1S_1 : You recover the original value S1S_1 by applying the private key:
S1=(Cd)(modM) S_1 = (C^d) \pmod M
  1. Final Encoding: You assemble the 16-byte block (S1,S2)(S_1, S_2) and pass it through the Base64 encoder using the custom alphabet located at address 0x404048.
b. The Invertibility Condition
  • If the modulus MM is 64-bit: The system is fully invertible in a fraction of a second, because 64-bit factorization cannot resist modern algorithms (such as MPQS or GNFS).
  • If MM had been 2048-bit: The function would be mathematically invertible in theory, but practically unbreakable without knowing the private key dd , making brute-force Keygen creation impossible.
c. Summary

We can recover the Serial from the Name. This is not about guessing the Serial by brute force, but about solving the modular exponentiation equation by factorizing the 64-bit modulus present in the program's data.

   0x401700:    pusha                                      ; Save all general-purpose registers onto the stack[cite: 1]
   0x401701:    mov    ecx,DWORD PTR [esp+0x28]            ; Retrieve message size to hash from the stack[cite: 1]
   0x401705:    mov    esi,DWORD PTR [esp+0x2c]            ; Retrieve pointer to source data[cite: 1]
   0x401709:    mov    BYTE PTR ds:0x404288,0x1             ; Set hash initialization state flag to 1[cite: 1]
   0x401710:    mov    DWORD PTR ds:0x404284,ecx           ; Store current message size[cite: 1]
   0x401716:    mov    DWORD PTR ds:0x404270,0x67452301    ; MD5 initial constant (A)[cite: 1]
   0x401720:    mov    DWORD PTR ds:0x404274,0xefcdab89    ; MD5 initial constant (B)[cite: 1]
   0x40172a:    mov    DWORD PTR ds:0x404278,0x98badcfe    ; MD5 initial constant (C)[cite: 1]
   0x401734:    mov    DWORD PTR ds:0x40427c,0x10325476    ; MD5 initial constant (D)[cite: 1]
   0x40173e:    mov    DWORD PTR ds:0x404280,ecx           ; Copy total message size for final computation[cite: 1]
   0x401744:    cmp    DWORD PTR ds:0x404284,0x40          ; Check if buffer contains at least 64 bytes (0x40)[cite: 1]
   0x40174b:    jb     0x401dab                            ; If less than 64 bytes, jump to padding/completion stage[cite: 1]
   0x401751:    mov    eax,ds:0x404270                     ; Load current state A into EAX[cite: 1]
   0x401756:    mov    ebx,DWORD PTR ds:0x404274           ; Load current state B into EBX[cite: 1]
   0x40175c:    mov    ecx,DWORD PTR ds:0x404278           ; Load current state C into ECX[cite: 1]
   0x401762:    mov    edx,DWORD PTR ds:0x40427c           ; Load current state D into EDX[cite: 1]
   0x401768:    mov    ebp,ebx                             ; Copy B to EBP for F(B,C,D) calculation[cite: 1]
   0x40176a:    mov    edi,ebx                             ; Copy B to EDI[cite: 1]
   0x40176c:    not    ebp                                 ; EBP = NOT B[cite: 1]
   0x40176e:    and    edi,ecx                             ; EDI = B AND C[cite: 1]
   0x401770:    and    ebp,edx                             ; EBP = (NOT B) AND D[cite: 1]
   0x401772:    add    eax,DWORD PTR [esi]                 ; A = A + M[0][cite: 1]
   0x401774:    or     edi,ebp                             ; EDI = F(B,C,D) = (B AND C) OR ((NOT B) AND D)[cite: 1]
   0x401776:    lea    eax,[edi+eax*1-0x28955b88]          ; A = A + F(B,C,D) + K[0] (0xd76aa478)[cite: 1]
   0x40177d:    rol    eax,0x7                             ; A = A ROL 7[cite: 1]
   0x401780:    add    eax,ebx                             ; A = A + B[cite: 1]
   0x401782:    mov    ebp,eax                             ; Copy A to EBP[cite: 1]
   0x401784:    mov    edi,eax                             ; Copy A to EDI[cite: 1]
   0x401786:    not    ebp                                 ; EBP = NOT A[cite: 1]
   0x401788:    and    edi,ebx                             ; EDI = A AND B[cite: 1]
   0x40178a:    and    ebp,ecx                             ; EBP = (NOT A) AND C[cite: 1]
   0x40178c:    add    edx,DWORD PTR [esi+0x4]             ; D = D + M[1][cite: 1]
   0x40178f:    or     edi,ebp                             ; EDI = F(A,B,C)[cite: 1]
   0x401791:    lea    edx,[edi+edx*1-0x173848aa]          ; D = D + F(A,B,C) + K[1][cite: 1]
   0x401798:    rol    edx,0xc                             ; D = D ROL 12[cite: 1]
   0x40179b:    add    edx,eax                             ; D = D + A[cite: 1]
   0x40179d:    mov    ebp,edx                             ; Copy D to EBP[cite: 1]
   0x40179f:    mov    edi,edx                             ; Copy D to EDI[cite: 1]
   0x4017a1:    not    ebp                                 ; EBP = NOT D[cite: 1]
   0x4017a3:    and    edi,eax                             ; EDI = D AND A[cite: 1]
   0x4017a5:    and    ebp,ebx                             ; EBP = (NOT D) AND B[cite: 1]
   0x4017a7:    add    ecx,DWORD PTR [esi+0x8]             ; C = C + M[2][cite: 1]
   0x4017aa:    or     edi,ebp                             ; EDI = F(D,A,B)[cite: 1]
   0x4017ac:    lea    ecx,[edi+ecx*1+0x242070db]          ; C = C + F(D,A,B) + K[2][cite: 1]
   0x4017b3:    rol    ecx,0x11                            ; C = C ROL 17[cite: 1]
   0x4017b6:    add    ecx,edx                             ; C = C + D[cite: 1]
   0x4017b8:    mov    ebp,ecx                             ; Copy C to EBP[cite: 1]
   0x4017ba:    mov    edi,ecx                             ; Copy C to EDI[cite: 1]
   0x4017bc:    not    ebp                                 ; EBP = NOT C[cite: 1]
   0x4017be:    and    edi,edx                             ; EDI = C AND D[cite: 1]
   0x4017c0:    and    ebp,eax                             ; EBP = (NOT C) AND A[cite: 1]
   0x4017c2:    add    ebx,DWORD PTR [esi+0xc]             ; B = B + M[3][cite: 1]
   0x4017c5:    or     edi,ebp                             ; EDI = F(C,D,A)[cite: 1]
   0x4017c7:    lea    ebx,[edi+ebx*1-0x3e423112]          ; B = B + F(C,D,A) + K[3][cite: 1]
   0x4017ce:    rol    ebx,0x16                            ; B = B ROL 22[cite: 1]
   0x4017d1:    add    ebx,ecx                             ; B = B + C[cite: 1]
   0x4017d3:    mov    ebp,ebx                             ; MD5 Operation Round 1, step 5[cite: 1]
   0x4017d5:    mov    edi,ebx                             ; Prepare bitwise masks[cite: 1]
   0x4017d7:    not    ebp                                 ; Invert B[cite: 1]
   0x4017d9:    and    edi,ecx                             ; B AND C[cite: 1]
   0x4017db:    and    ebp,edx                             ; (NOT B) AND D[cite: 1]
   0x4017dd:    add    eax,DWORD PTR [esi+0x10]             ; Add M[4][cite: 1]
   0x4017e0:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x4017e2:    lea    eax,[edi+eax*1-0xa83f051]           ; Add constant K[4][cite: 1]
   0x4017e9:    rol    eax,0x7                             ; Bitwise circular shift of 7 bits[cite: 1]
   0x4017ec:    add    eax,ebx                             ; Accumulate into A[cite: 1]
   0x4017ee:    mov    ebp,eax                             ; MD5 Operation Round 1, step 6[cite: 1]
   0x4017f0:    mov    edi,eax                             ; Prepare bitwise masks[cite: 1]
   0x4017f2:    not    ebp                                 ; Invert A[cite: 1]
   0x4017f4:    and    edi,ebx                             ; A AND B[cite: 1]
   0x4017f6:    and    ebp,ecx                             ; (NOT A) AND C[cite: 1]
   0x4017f8:    add    edx,DWORD PTR [esi+0x14]             ; Add M[5][cite: 1]
   0x4017fb:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x4017fd:    lea    edx,[edi+edx*1+0x4787c62a]          ; Add constant K[5][cite: 1]
   0x401804:    rol    edx,0xc                             ; Bitwise circular shift of 12 bits[cite: 1]
   0x401807:    add    edx,eax                             ; Accumulate into D[cite: 1]
   0x401809:    mov    ebp,edx                             ; MD5 Operation Round 1, step 7[cite: 1]
   0x40180b:    mov    edi,edx                             ; Prepare bitwise masks[cite: 1]
   0x40180d:    not    ebp                                 ; Invert D[cite: 1]
   0x40180f:    and    edi,eax                             ; D AND A[cite: 1]
   0x401811:    and    ebp,ebx                             ; (NOT D) AND B[cite: 1]
   0x401813:    add    ecx,DWORD PTR [esi+0x18]             ; Add M[6][cite: 1]
   0x401816:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x401818:    lea    ecx,[edi+ecx*1-0x57cfb9ed]          ; Add constant K[6][cite: 1]
   0x40181f:    rol    ecx,0x11                            ; Bitwise circular shift of 17 bits[cite: 1]
   0x401822:    add    ecx,edx                             ; Accumulate into C[cite: 1]
   0x401824:    mov    ebp,ecx                             ; MD5 Operation Round 1, step 8[cite: 1]
   0x401826:    mov    edi,ecx                             ; Prepare bitwise masks[cite: 1]
   0x401828:    not    ebp                                 ; Invert C[cite: 1]
   0x40182a:    and    edi,edx                             ; C AND D[cite: 1]
   0x40182c:    and    ebp,eax                             ; (NOT C) AND A[cite: 1]
   0x40182e:    add    ebx,DWORD PTR [esi+0x1c]             ; Add M[7][cite: 1]
   0x401831:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x401833:    lea    ebx,[edi+ebx*1-0x2b96aff]           ; Add constant K[7][cite: 1]
   0x40183a:    rol    ebx,0x16                            ; Bitwise circular shift of 22 bits[cite: 1]
   0x40183d:    add    ebx,ecx                             ; Accumulate into B[cite: 1]
   0x40183f:    mov    ebp,ebx                             ; MD5 Operation Round 1, step 9[cite: 1]
   0x401841:    mov    edi,ebx                             ; Prepare bitwise masks[cite: 1]
   0x401843:    not    ebp                                 ; Invert B[cite: 1]
   0x401845:    and    edi,ecx                             ; B AND C[cite: 1]
   0x401847:    and    ebp,edx                             ; (NOT B) AND D[cite: 1]
   0x401849:    add    eax,DWORD PTR [esi+0x20]             ; Add M[8][cite: 1]
   0x40184c:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x40184e:    lea    eax,[edi+eax*1+0x698098d8]          ; Add constant K[8][cite: 1]
   0x401855:    rol    eax,0x7                             ; Bitwise circular shift of 7 bits[cite: 1]
   0x401858:    add    eax,ebx                             ; Accumulate into A[cite: 1]
   0x40185a:    mov    ebp,eax                             ; MD5 Operation Round 1, step 10[cite: 1]
   0x40185c:    mov    edi,eax                             ; Prepare bitwise masks[cite: 1]
   0x40185e:    not    ebp                                 ; Invert A[cite: 1]
   0x401860:    and    edi,ebx                             ; A AND B[cite: 1]
   0x401862:    and    ebp,ecx                             ; (NOT A) AND C[cite: 1]
   0x401864:    add    edx,DWORD PTR [esi+0x24]             ; Add M[9][cite: 1]
   0x401867:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x401869:    lea    edx,[edi+edx*1-0x74bb0851]          ; Add constant K[9][cite: 1]
   0x401870:    rol    edx,0xc                             ; Bitwise circular shift of 12 bits[cite: 1]
   0x401873:    add    edx,eax                             ; Accumulate into D[cite: 1]
   0x401875:    mov    ebp,edx                             ; MD5 Operation Round 1, step 11[cite: 1]
   0x401877:    mov    edi,edx                             ; Prepare bitwise masks[cite: 1]
   0x401879:    not    ebp                                 ; Invert D[cite: 1]
   0x40187b:    and    edi,eax                             ; D AND A[cite: 1]
   0x40187d:    and    ebp,ebx                             ; (NOT D) AND B[cite: 1]
   0x40187f:    add    ecx,DWORD PTR [esi+0x28]             ; Add M[10][cite: 1]
   0x401882:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x401884:    lea    ecx,[edi+ecx*1-0xa44f]              ; Add constant K[10][cite: 1]
   0x40188b:    rol    ecx,0x11                            ; Bitwise circular shift of 17 bits[cite: 1]
   0x40188e:    add    ecx,edx                             ; Accumulate into C[cite: 1]
   0x401890:    mov    ebp,ecx                             ; MD5 Operation Round 1, step 12[cite: 1]
   0x401892:    mov    edi,ecx                             ; Prepare bitwise masks[cite: 1]
   0x401894:    not    ebp                                 ; Invert C[cite: 1]
   0x401896:    and    edi,edx                             ; C AND D[cite: 1]
   0x401898:    and    ebp,eax                             ; (NOT C) AND A[cite: 1]
   0x40189a:    add    ebx,DWORD PTR [esi+0x2c]             ; Add M[11][cite: 1]
   0x40189d:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x40189f:    lea    ebx,[edi+ebx*1-0x76a32842]          ; Add constant K[11][cite: 1]
   0x4018a6:    rol    ebx,0x16                            ; Bitwise circular shift of 22 bits[cite: 1]
   0x4018a9:    add    ebx,ecx                             ; Accumulate into B[cite: 1]
   0x4018ab:    mov    ebp,ebx                             ; MD5 Operation Round 1, step 13[cite: 1]
   0x4018ad:    mov    edi,ebx                             ; Prepare bitwise masks[cite: 1]
   0x4018af:    not    ebp                                 ; Invert B[cite: 1]
   0x4018b1:    and    edi,ecx                             ; B AND C[cite: 1]
   0x4018b3:    and    ebp,edx                             ; (NOT B) AND D[cite: 1]
   0x4018b5:    add    eax,DWORD PTR [esi+0x30]             ; Add M[12][cite: 1]
   0x4018b8:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x4018ba:    lea    eax,[edi+eax*1+0x6b901122]          ; Add constant K[12][cite: 1]
   0x4018c1:    rol    eax,0x7                             ; Bitwise circular shift of 7 bits[cite: 1]
   0x4018c4:    add    eax,ebx                             ; Accumulate into A[cite: 1]
   0x4018c6:    mov    ebp,eax                             ; MD5 Operation Round 1, step 14[cite: 1]
   0x4018c8:    mov    edi,eax                             ; Prepare bitwise masks[cite: 1]
   0x4018ca:    not    ebp                                 ; Invert A[cite: 1]
   0x4018cc:    and    edi,ebx                             ; A AND B[cite: 1]
   0x4018ce:    and    ebp,ecx                             ; (NOT A) AND C[cite: 1]
   0x4018d0:    add    edx,DWORD PTR [esi+0x34]             ; Add M[13][cite: 1]
   0x4018d3:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x4018d5:    lea    edx,[edi+edx*1-0x2678e6d]           ; Add constant K[13][cite: 1]
   0x4018dc:    rol    edx,0xc                             ; Bitwise circular shift of 12 bits[cite: 1]
   0x4018df:    add    edx,eax                             ; Accumulate into D[cite: 1]
   0x4018e1:    mov    ebp,edx                             ; MD5 Operation Round 1, step 15[cite: 1]
   0x4018e3:    mov    edi,edx                             ; Prepare bitwise masks[cite: 1]
   0x4018e5:    not    ebp                                 ; Invert D[cite: 1]
   0x4018e7:    and    edi,eax                             ; D AND A[cite: 1]
   0x4018e9:    and    ebp,ebx                             ; (NOT D) AND B[cite: 1]
   0x4018eb:    add    ecx,DWORD PTR [esi+0x38]             ; Add M[14][cite: 1]
   0x4018ee:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x4018f0:    lea    ecx,[edi+ecx*1-0x5986bc72]          ; Add constant K[14][cite: 1]
   0x4018f7:    rol    ecx,0x11                            ; Bitwise circular shift of 17 bits[cite: 1]
   0x4018fa:    add    ecx,edx                             ; Accumulate into C[cite: 1]
   0x4018fc:    mov    ebp,ecx                             ; MD5 Operation Round 1, step 16[cite: 1]
   0x4018fe:    mov    edi,ecx                             ; Prepare bitwise masks[cite: 1]
   0x401900:    not    ebp                                 ; Invert C[cite: 1]
   0x401902:    and    edi,edx                             ; C AND D[cite: 1]
   0x401904:    and    ebp,eax                             ; (NOT C) AND A[cite: 1]
   0x401906:    add    ebx,DWORD PTR [esi+0x3c]             ; Add M[15][cite: 1]
   0x401909:    or     edi,ebp                             ; Combine logical results[cite: 1]
   0x40190b:    lea    ebx,[edi+ebx*1+0x49b40821]          ; Add constant K[15][cite: 1]
   0x401912:    rol    ebx,0x16                            ; Bitwise circular shift of 22 bits[cite: 1]
   0x401915:    add    ebx,ecx                             ; End of Round 1[cite: 1]
   0x401917:    mov    ebp,edx                             ; Start of Round 2 - G(B,C,D) = (B AND D) OR (C AND NOT D)[cite: 1]
   0x401919:    mov    edi,edx                             ; Copy D to EDI[cite: 1]
   0x40191b:    not    ebp                                 ; EBP = NOT D[cite: 1]
   0x40191d:    and    edi,ebx                             ; EDI = D AND B[cite: 1]
   0x40191f:    and    ebp,ecx                             ; EBP = (NOT D) AND C[cite: 1]
   0x401921:    add    eax,DWORD PTR [esi+0x4]              ; A = A + M[1][cite: 1]
   0x401924:    or     edi,ebp                             ; EDI = G(B,C,D)[cite: 1]
   0x401926:    lea    eax,[edi+eax*1-0x9e1da9e]           ; A = A + G(B,C,D) + K[16][cite: 1]
   0x40192d:    rol    eax,0x5                             ; Bitwise circular shift of 5 bits[cite: 1]
   0x401930:    add    eax,ebx                             ; A = A + B[cite: 1]
   0x401932:    mov    ebp,ecx                             ; MD5 Operation Round 2, step 2[cite: 1]
   0x401934:    mov    edi,ecx                             ; Prepare G function[cite: 1]
   0x401936:    not    ebp                                 ; Invert C[cite: 1]
   0x401938:    and    edi,eax                             ; C AND A[cite: 1]
   0x40193a:    and    ebp,ebx                             ; (NOT C) AND B[cite: 1]
   0x40193c:    add    edx,DWORD PTR [esi+0x18]             ; Add M[6][cite: 1]
   0x40193f:    or     edi,ebp                             ; Combine[cite: 1]
   0x401941:    lea    edx,[edi+edx*1-0x3fbf4cc0]          ; Add constant K[17][cite: 1]
   0x401948:    rol    edx,0x9                             ; Bitwise circular shift of 9 bits[cite: 1]
   0x40194b:    add    edx,eax                             ; Accumulate[cite: 1]
   0x40194d:    mov    ebp,ebx                             ; MD5 Operation Round 2, step 3[cite: 1]
   0x40194f:    mov    edi,ebx                             ; Prepare G function[cite: 1]
   0x401951:    not    ebp                                 ; Invert B[cite: 1]
   0x401953:    and    edi,edx                             ; B AND D[cite: 1]
   0x401955:    and    ebp,eax                             ; (NOT B) AND A[cite: 1]
   0x401957:    add    ecx,DWORD PTR [esi+0x2c]             ; Add M[11][cite: 1]
   0x40195a:    or     edi,ebp                             ; Combine[cite: 1]
   0x40195c:    lea    ecx,[edi+ecx*1+0x265e5a51]          ; Add constant K[18][cite: 1]
   0x401963:    rol    ecx,0xe                             ; Bitwise circular shift of 14 bits[cite: 1]
   0x401966:    add    ecx,edx                             ; Accumulate[cite: 1]
   0x401968:    mov    ebp,eax                             ; MD5 Operation Round 2, step 4[cite: 1]
   0x40196a:    mov    edi,eax                             ; Prepare G function[cite: 1]
   0x40196c:    not    ebp                                 ; Invert A[cite: 1]
   0x40196e:    and    edi,ecx                             ; A AND C[cite: 1]
   0x401970:    and    ebp,edx                             ; (NOT A) AND D[cite: 1]
   0x401972:    add    ebx,DWORD PTR [esi]                 ; Add M[0][cite: 1]
   0x401974:    or     edi,ebp                             ; Combine[cite: 1]
   0x401976:    lea    ebx,[edi+ebx*1-0x16493856]          ; Add constant K[19][cite: 1]
   0x40197d:    rol    ebx,0x14                            ; Bitwise circular shift of 20 bits[cite: 1]
   0x401980:    add    ebx,ecx                             ; Accumulate[cite: 1]
   0x401982:    mov    ebp,edx                             ; MD5 Operation Round 2, step 5[cite: 1]
   0x401984:    mov    edi,edx                             ; Prepare G function[cite: 1]
   0x401986:    not    ebp                                 ; Invert D[cite: 1]
   0x401988:    and    edi,ebx                             ; D AND B[cite: 1]
   0x40198a:    and    ebp,ecx                             ; (NOT D) AND C[cite: 1]
   0x40198c:    add    eax,DWORD PTR [esi+0x14]             ; Add M[5][cite: 1]
   0x40198f:    or     edi,ebp                             ; Combine[cite: 1]
   0x401991:    lea    eax,[edi+eax*1-0x29d0efa3]          ; Add constant K[20][cite: 1]
   0x401998:    rol    eax,0x5                             ; Bitwise circular shift of 5 bits[cite: 1]
   0x40199b:    add    eax,ebx                             ; Accumulate[cite: 1]
   0x40199d:    mov    ebp,ecx                             ; MD5 Operation Round 2, step 6[cite: 1]
   0x40199f:    mov    edi,ecx                             ; Prepare G function[cite: 1]
   0x4019a1:    not    ebp                                 ; Invert C[cite: 1]
   0x4019a3:    and    edi,eax                             ; C AND A[cite: 1]
   0x4019a5:    and    ebp,ebx                             ; (NOT C) AND B[cite: 1]
   0x4019a7:    add    edx,DWORD PTR [esi+0x28]             ; Add M[10][cite: 1]
   0x4019aa:    or     edi,ebp                             ; Combine[cite: 1]
   0x4019ac:    lea    edx,[edi+edx*1+0x2441453]           ; Add constant K[21][cite: 1]
   0x4019b3:    rol    edx,0x9                             ; Bitwise circular shift of 9 bits[cite: 1]
   0x4019b6:    add    edx,eax                             ; Accumulate[cite: 1]
   0x4019b8:    mov    ebp,ebx                             ; MD5 Operation Round 2, step 7[cite: 1]
   0x4019ba:    mov    edi,ebx                             ; Prepare G function[cite: 1]
   0x4019bc:    not    ebp                                 ; Invert B[cite: 1]
   0x4019be:    and    edi,edx                             ; B AND D[cite: 1]
   0x4019c0:    and    ebp,eax                             ; (NOT B) AND A[cite: 1]
   0x4019c2:    add    ecx,DWORD PTR [esi+0x3c]             ; Add M[15][cite: 1]
   0x4019c5:    or     edi,ebp                             ; Combine[cite: 1]
   0x4019c7:    lea    ecx,[edi+ecx*1-0x275e197f]          ; Add constant K[22][cite: 1]
   0x4019ce:    rol    ecx,0xe                             ; Bitwise circular shift of 14 bits[cite: 1]
   0x4019d1:    add    ecx,edx                             ; Accumulate[cite: 1]
   0x4019d3:    mov    ebp,eax                             ; MD5 Operation Round 2, step 8[cite: 1]
   0x4019d5:    mov    edi,eax                             ; Prepare G function[cite: 1]
   0x4019d7:    not    ebp                                 ; Invert A[cite: 1]
   0x4019d9:    and    edi,ecx                             ; A AND C[cite: 1]
   0x4019db:    and    ebp,edx                             ; (NOT A) AND D[cite: 1]
   0x4019dd:    add    ebx,DWORD PTR [esi+0x10]             ; Add M[4][cite: 1]
   0x4019e0:    or     edi,ebp                             ; Combine[cite: 1]
   0x4019e2:    lea    ebx,[edi+ebx*1-0x182c0438]          ; Add constant K[23][cite: 1]
   0x4019e9:    rol    ebx,0x14                            ; Bitwise circular shift of 20 bits[cite: 1]
   0x4019ec:    add    ebx,ecx                             ; Accumulate[cite: 1]
   0x4019ee:    mov    ebp,edx                             ; MD5 Operation Round 2, step 9[cite: 1]
   0x4019f0:    mov    edi,edx                             ; Prepare G function[cite: 1]
   0x4019f2:    not    ebp                                 ; Invert D[cite: 1]
   0x4019f4:    and    edi,ebx                             ; D AND B[cite: 1]
   0x4019f6:    and    ebp,ecx                             ; (NOT D) AND C[cite: 1]
   0x4019f8:    add    eax,DWORD PTR [esi+0x24]             ; Add M[9][cite: 1]
   0x4019fb:    or     edi,ebp                             ; Combine[cite: 1]
   0x4019fd:    lea    eax,[edi+eax*1+0x21e1cde6]          ; Add constant K[24][cite: 1]
   0x401a04:    rol    eax,0x5                             ; Bitwise circular shift of 5 bits[cite: 1]
   0x401a07:    add    eax,ebx                             ; Accumulate[cite: 1]
   0x401a09:    mov    ebp,ecx                             ; MD5 Operation Round 2, step 10[cite: 1]
   0x401a0b:    mov    edi,ecx                             ; Prepare G function[cite: 1]
   0x401a0d:    not    ebp                                 ; Invert C[cite: 1]
   0x401a0f:    and    edi,eax                             ; C AND A[cite: 1]
   0x401a11:    and    ebp,ebx                             ; (NOT C) AND B[cite: 1]
   0x401a13:    add    edx,DWORD PTR [esi+0x38]             ; Add M[14][cite: 1]
   0x401a16:    or     edi,ebp                             ; Combine[cite: 1]
   0x401a18:    lea    edx,[edi+edx*1-0x3cc8f82a]          ; Add constant K[25][cite: 1]
   0x401a1f:    rol    edx,0x9                             ; Bitwise circular shift of 9 bits[cite: 1]
   0x401a22:    add    edx,eax                             ; Accumulate[cite: 1]
   0x401a24:    mov    ebp,ebx                             ; MD5 Operation Round 2, step 11[cite: 1]
   0x401a26:    mov    edi,ebx                             ; Prepare G function[cite: 1]
   0x401a28:    not    ebp                                 ; Invert B[cite: 1]
   0x401a2a:    and    edi,edx                             ; B AND D[cite: 1]
   0x401a2c:    and    ebp,eax                             ; (NOT B) AND A[cite: 1]
   0x401a2e:    add    ecx,DWORD PTR [esi+0xc]              ; Add M[3][cite: 1]
   0x401a31:    or     edi,ebp                             ; Combine[cite: 1]
   0x401a33:    lea    ecx,[edi+ecx*1-0xb2af279]           ; Add constant K[26][cite: 1]
   0x401a3a:    rol    ecx,0xe                             ; Bitwise circular shift of 14 bits[cite: 1]
   0x401a3d:    add    ecx,edx                             ; Accumulate[cite: 1]
   0x401a3f:    mov    ebp,eax                             ; MD5 Operation Round 2, step 12[cite: 1]
   0x401a41:    mov    edi,eax                             ; Prepare G function[cite: 1]
   0x401a43:    not    ebp                                 ; Invert A[cite: 1]
   0x401a45:    and    edi,ecx                             ; A AND C[cite: 1]
   0x401a47:    and    ebp,edx                             ; (NOT A) AND D[cite: 1]
   0x401a49:    add    ebx,DWORD PTR [esi+0x20]             ; Add M[8][cite: 1]
   0x401a4c:    or     edi,ebp                             ; Combine[cite: 1]
   0x401a4e:    lea    ebx,[edi+ebx*1+0x455a14ed]          ; Add constant K[27][cite: 1]
   0x401a55:    rol    ebx,0x14                            ; Bitwise circular shift of 20 bits[cite: 1]
   0x401a58:    add    ebx,ecx                             ; Accumulate[cite: 1]
   0x401a5a:    mov    ebp,edx                             ; MD5 Operation Round 2, step 13[cite: 1]
   0x401a5c:    mov    edi,edx                             ; Prepare G function[cite: 1]
   0x401a5e:    not    ebp                                 ; Invert D[cite: 1]
   0x401a60:    and    edi,ebx                             ; D AND B[cite: 1]
   0x401a62:    and    ebp,ecx                             ; (NOT D) AND C[cite: 1]
   0x401a64:    add    eax,DWORD PTR [esi+0x34]             ; Add M[13][cite: 1]
   0x401a67:    or     edi,ebp                             ; Combine[cite: 1]
   0x401a69:    lea    eax,[edi+eax*1-0x561c16fb]          ; Add constant K[28][cite: 1]
   0x401a70:    rol    eax,0x5                             ; Bitwise circular shift of 5 bits[cite: 1]
   0x401a73:    add    eax,ebx                             ; Accumulate[cite: 1]
   0x401a75:    mov    ebp,ecx                             ; MD5 Operation Round 2, step 14[cite: 1]
   0x401a77:    mov    edi,ecx                             ; Prepare G function[cite: 1]
   0x401a79:    not    ebp                                 ; Invert C[cite: 1]
   0x401a7b:    and    edi,eax                             ; C AND A[cite: 1]
   0x401a7d:    and    ebp,ebx                             ; (NOT C) AND B[cite: 1]
   0x401a7f:    add    edx,DWORD PTR [esi+0x8]              ; Add M[2][cite: 1]
   0x401a82:    or     edi,ebp                             ; Combine[cite: 1]
   0x401a84:    lea    edx,[edi+edx*1-0x3105c08]           ; Add constant K[29][cite: 1]
   0x401a8b:    rol    edx,0x9                             ; Bitwise circular shift of 9 bits[cite: 1]
   0x401a8e:    add    edx,eax                             ; Accumulate[cite: 1]
   0x401a90:    mov    ebp,ebx                             ; MD5 Operation Round 2, step 15[cite: 1]
   0x401a92:    mov    edi,ebx                             ; Prepare G function[cite: 1]
   0x401a94:    not    ebp                                 ; Invert B[cite: 1]
   0x401a96:    and    edi,edx                             ; B AND D[cite: 1]
   0x401a98:    and    ebp,eax                             ; (NOT B) AND A[cite: 1]
   0x401a9a:    add    ecx,DWORD PTR [esi+0x1c]             ; Add M[7][cite: 1]
   0x401a9d:    or     edi,ebp                             ; Combine[cite: 1]
   0x401a9f:    lea    ecx,[edi+ecx*1+0x676f02d9]          ; Add constant K[30][cite: 1]
   0x401aa6:    rol    ecx,0xe                             ; Bitwise circular shift of 14 bits[cite: 1]
   0x401aa9:    add    ecx,edx                             ; Accumulate[cite: 1]
   0x401aab:    mov    ebp,eax                             ; MD5 Operation Round 2, step 16[cite: 1]
   0x401aad:    mov    edi,eax                             ; Prepare G function[cite: 1]
   0x401aaf:    not    ebp                                 ; Invert A[cite: 1]
   0x401ab1:    and    edi,ecx                             ; A AND C[cite: 1]
   0x401ab3:    and    ebp,edx                             ; (NOT A) AND D[cite: 1]
   0x401ab5:    add    ebx,DWORD PTR [esi+0x30]             ; Add M[12][cite: 1]
   0x401ab8:    or     edi,ebp                             ; Combine[cite: 1]
   0x401aba:    lea    ebx,[edi+ebx*1-0x72d5b376]          ; Add constant K[31][cite: 1]
   0x401ac1:    rol    ebx,0x14                            ; Bitwise circular shift of 20 bits[cite: 1]
   0x401ac4:    add    ebx,ecx                             ; End of Round 2[cite: 1]
   0x401ac6:    mov    ebp,edx                             ; Start of Round 3 - H(B,C,D) = B XOR C XOR D[cite: 1]
   0x401ac8:    add    eax,DWORD PTR [esi+0x14]             ; A = A + M[5][cite: 1]
   0x401acb:    xor    ebp,ecx                             ; EBP = D XOR C[cite: 1]
   0x401acd:    xor    ebp,ebx                             ; EBP = D XOR C XOR B[cite: 1]
   0x401acf:    lea    eax,[ebp+eax*1-0x5c6be]             ; A = A + H(B,C,D) + K[32][cite: 1]
   0x401ad6:    rol    eax,0x4                             ; Bitwise circular shift of 4 bits[cite: 1]
   0x401ad9:    add    eax,ebx                             ; A = A + B[cite: 1]
   0x401adb:    mov    ebp,ecx                             ; MD5 Operation Round 3, step 2[cite: 1]
   0x401add:    add    edx,DWORD PTR [esi+0x20]             ; Add M[8][cite: 1]
   0x401ae0:    xor    ebp,ebx                             ; C XOR B[cite: 1]
   0x401ae2:    xor    ebp,eax                             ; C XOR B XOR A[cite: 1]
   0x401ae4:    lea    edx,[ebp+edx*1-0x788e097f]          ; Add constant K[33][cite: 1]
   0x401aeb:    rol    edx,0xb                             ; Bitwise circular shift of 11 bits[cite: 1]
   0x401aee:    add    edx,eax                             ; Accumulate into D[cite: 1]
   0x401af0:    mov    ebp,ebx                             ; MD5 Operation Round 3, step 3[cite: 1]
   0x401af2:    add    ecx,DWORD PTR [esi+0x2c]             ; Add M[11][cite: 1]
   0x401af5:    xor    ebp,eax                             ; B XOR A[cite: 1]
   0x401af7:    xor    ebp,edx                             ; B XOR A XOR D[cite: 1]
   0x401af9:    lea    ecx,[ebp+ecx*1+0x6d9d6122]          ; Add constant K[34][cite: 1]
   0x401b00:    rol    ecx,0x10                            ; Bitwise circular shift of 16 bits[cite: 1]
   0x401b03:    add    ecx,edx                             ; Accumulate into C[cite: 1]
   0x401b05:    mov    ebp,eax                             ; MD5 Operation Round 3, step 4[cite: 1]
   0x401b07:    add    ebx,DWORD PTR [esi+0x38]             ; Add M[14][cite: 1]
   0x401b0a:    xor    ebp,edx                             ; A XOR D[cite: 1]
   0x401b0c:    xor    ebp,ecx                             ; A XOR D XOR C[cite: 1]
   0x401b0e:    lea    ebx,[ebp+ebx*1-0x21ac7f4]           ; Add constant K[35][cite: 1]
   0x401b15:    rol    ebx,0x17                            ; Bitwise circular shift of 23 bits[cite: 1]
   0x401b18:    add    ebx,ecx                             ; Accumulate into B[cite: 1]
   0x401b1a:    mov    ebp,edx                             ; MD5 Operation Round 3, step 5[cite: 1]
   0x401b1c:    add    eax,DWORD PTR [esi+0x4]              ; Add M[1][cite: 1]
   0x401b1f:    xor    ebp,ecx                             ; D XOR C[cite: 1]
   0x401b21:    xor    ebp,ebx                             ; D XOR C XOR B[cite: 1]
   0x401b23:    lea    eax,[ebp+eax*1-0x5b4115bc]          ; Add constant K[36][cite: 1]
   0x401b2a:    rol    eax,0x4                             ; Bitwise circular shift of 4 bits[cite: 1]
   0x401b2d:    add    eax,ebx                             ; Accumulate[cite: 1]
   0x401b2f:    mov    ebp,ecx                             ; MD5 Operation Round 3, step 6[cite: 1]
   0x401b31:    add    edx,DWORD PTR [esi+0x10]             ; Add M[4][cite: 1]
   0x401b34:    xor    ebp,ebx                             ; C XOR B[cite: 1]
   0x401b36:    xor    ebp,eax                             ; C XOR B XOR A[cite: 1]
   0x401b38:    lea    edx,[ebp+edx*1+0x4bdecfa9]          ; Add constant K[37][cite: 1]
   0x401b3f:    rol    edx,0xb                             ; Bitwise circular shift of 11 bits[cite: 1]
   0x401b42:    add    edx,eax                             ; Accumulate[cite: 1]
   0x401b44:    mov    ebp,ebx                             ; MD5 Operation Round 3, step 7[cite: 1]
   0x401b46:    add    ecx,DWORD PTR [esi+0x1c]             ; Add M[7][cite: 1]
   0x401b49:    xor    ebp,eax                             ; B XOR A[cite: 1]
   0x401b4b:    xor    ebp,edx                             ; B XOR A XOR D[cite: 1]
   0x401b4d:    lea    ecx,[ebp+ecx*1-0x944b4a0]           ; Add constant K[38][cite: 1]
   0x401b54:    rol    ecx,0x10                            ; Bitwise circular shift of 16 bits[cite: 1]
   0x401b57:    add    ecx,edx                             ; Accumulate[cite: 1]
   0x401b59:    mov    ebp,eax                             ; MD5 Operation Round 3, step 8[cite: 1]
   0x401b5b:    add    ebx,DWORD PTR [esi+0x28]             ; Add M[10][cite: 1]
   0x401b5e:    xor    ebp,edx                             ; A XOR D[cite: 1]
   0x401b60:    xor    ebp,ecx                             ; A XOR D XOR C[cite: 1]
   0x401b62:    lea    ebx,[ebp+ebx*1-0x41404390]          ; Add constant K[39][cite: 1]
   0x401b69:    rol    ebx,0x17                            ; Bitwise circular shift of 23 bits[cite: 1]
   0x401b6c:    add    ebx,ecx                             ; Accumulate[cite: 1]
   0x401b6e:    mov    ebp,edx                             ; MD5 Operation Round 3, step 9[cite: 1]
   0x401b70:    add    eax,DWORD PTR [esi+0x34]             ; Add M[13][cite: 1]
   0x401b73:    xor    ebp,ecx                             ; D XOR C[cite: 1]
   0x401b75:    xor    ebp,ebx                             ; D XOR C XOR B[cite: 1]
   0x401b77:    lea    eax,[ebp+eax*1+0x289b7ec6]          ; Add constant K[40][cite: 1]
   0x401b7e:    rol    eax,0x4                             ; Bitwise circular shift of 4 bits[cite: 1]
   0x401b81:    add    eax,ebx                             ; Accumulate[cite: 1]
   0x401b83:    mov    ebp,ecx                             ; MD5 Operation Round 3, step 10[cite: 1]
   0x401b85:    add    edx,DWORD PTR [esi]                 ; Add M[0][cite: 1]
   0x401b87:    xor    ebp,ebx                             ; C XOR B[cite: 1]
   0x401b89:    xor    ebp,eax                             ; C XOR B XOR A[cite: 1]
   0x401b8b:    lea    edx,[ebp+edx*1-0x155ed806]          ; Add constant K[41][cite: 1]
   0x401b92:    rol    edx,0xb                             ; Bitwise circular shift of 11 bits[cite: 1]
   0x401b95:    add    edx,eax                             ; Accumulate[cite: 1]
   0x401b97:    mov    ebp,ebx                             ; MD5 Operation Round 3, step 11[cite: 1]
   0x401b99:    add    ecx,DWORD PTR [esi+0xc]              ; Add M[3][cite: 1]
   0x401b9c:    xor    ebp,eax                             ; B XOR A[cite: 1]
   0x401b9e:    xor    ebp,edx                             ; B XOR A XOR D[cite: 1]
   0x401ba0:    lea    ecx,[ebp+ecx*1-0x2b10cf7b]          ; Add constant K[42][cite: 1]
   0x401ba7:    rol    ecx,0x10                            ; Bitwise circular shift of 16 bits[cite: 1]
   0x401baa:    add    ecx,edx                             ; Accumulate[cite: 1]
   0x401bac:    mov    ebp,eax                             ; MD5 Operation Round 3, step 12[cite: 1]
   0x401bae:    add    ebx,DWORD PTR [esi+0x18]             ; Add M[6][cite: 1]
   0x401bb1:    xor    ebp,edx                             ; A XOR D[cite: 1]
   0x401bb3:    xor    ebp,ecx                             ; A XOR D XOR C[cite: 1]
   0x401bb5:    lea    ebx,[ebp+ebx*1+0x4881d05]           ; Add constant K[43][cite: 1]
   0x401bbc:    rol    ebx,0x17                            ; Bitwise circular shift of 23 bits[cite: 1]
   0x401bbf:    add    ebx,ecx                             ; Accumulate[cite: 1]
   0x401bc1:    mov    ebp,edx                             ; MD5 Operation Round 3, step 13[cite: 1]
   0x401bc3:    add    eax,DWORD PTR [esi+0x24]             ; Add M[9][cite: 1]
   0x401bc6:    xor    ebp,ecx                             ; D XOR C[cite: 1]
   0x401bc8:    xor    ebp,ebx                             ; D XOR C XOR B[cite: 1]
   0x401bca:    lea    eax,[ebp+eax*1-0x262b2fc7]          ; Add constant K[44][cite: 1]
   0x401bd1:    rol    eax,0x4                             ; Bitwise circular shift of 4 bits[cite: 1]
   0x401bd4:    add    eax,ebx                             ; Accumulate[cite: 1]
   0x401bd6:    mov    ebp,ecx                             ; MD5 Operation Round 3, step 14[cite: 1]
   0x401bd8:    add    edx,DWORD PTR [esi+0x30]             ; Add M[12][cite: 1]
   0x401bdb:    xor    ebp,ebx                             ; C XOR B[cite: 1]
   0x401bdd:    xor    ebp,eax                             ; C XOR B XOR A[cite: 1]
   0x401bdf:    lea    edx,[ebp+edx*1-0x1924661b]          ; Add constant K[45][cite: 1]
   0x401be6:    rol    edx,0xb                             ; Bitwise circular shift of 11 bits[cite: 1]
   0x401be9:    add    edx,eax                             ; Accumulate[cite: 1]
   0x401beb:    mov    ebp,ebx                             ; MD5 Operation Round 3, step 15[cite: 1]
   0x401bed:    add    ecx,DWORD PTR [esi+0x3c]             ; Add M[15][cite: 1]
   0x401bf0:    xor    ebp,eax                             ; B XOR A[cite: 1]
   0x401bf2:    xor    ebp,edx                             ; B XOR A XOR D[cite: 1]
   0x401bf4:    lea    ecx,[ebp+ecx*1+0x1fa27cf8]          ; Add constant K[46][cite: 1]
   0x401bfb:    rol    ecx,0x10                            ; Bitwise circular shift of 16 bits[cite: 1]
   0x401bfe:    add    ecx,edx                             ; Accumulate[cite: 1]
   0x401c00:    mov    ebp,eax                             ; MD5 Operation Round 3, step 16[cite: 1]
   0x401c02:    add    ebx,DWORD PTR [esi+0x8]              ; Add M[2][cite: 1]
   0x401c05:    xor    ebp,edx                             ; A XOR D[cite: 1]
   0x401c07:    xor    ebp,ecx                             ; A XOR D XOR C[cite: 1]
   0x401c09:    lea    ebx,[ebp+ebx*1-0x3b53a99b]          ; Add constant K[47][cite: 1]
   0x401c10:    rol    ebx,0x17                            ; Bitwise circular shift of 23 bits[cite: 1]
   0x401c13:    add    ebx,ecx                             ; End of Round 3[cite: 1]
   0x401c15:    mov    edi,edx                             ; Start of Round 4 - I(B,C,D) = C XOR (B OR NOT D)[cite: 1]
   0x401c17:    add    eax,DWORD PTR [esi]                 ; A = A + M[0][cite: 1]
   0x401c19:    not    edi                                 ; EDI = NOT D[cite: 1]
   0x401c1b:    or     edi,ebx                             ; EDI = B OR (NOT D)[cite: 1]
   0x401c1d:    xor    edi,ecx                             ; EDI = C XOR (B OR NOT D)[cite: 1]
   0x401c1f:    lea    eax,[edi+eax*1-0xbd6ddbc]           ; A = A + I(B,C,D) + K[48][cite: 1]
   0x401c26:    rol    eax,0x6                             ; Bitwise circular shift of 6 bits[cite: 1]
   0x401c29:    add    eax,ebx                             ; A = A + B[cite: 1]
   0x401c2b:    mov    edi,ecx                             ; MD5 Operation Round 4, step 2[cite: 1]
   0x401c2d:    add    edx,DWORD PTR [esi+0x1c]             ; Add M[7][cite: 1]
   0x401c30:    not    edi                                 ; NOT C[cite: 1]
   0x401c32:    or     edi,eax                             ; A OR (NOT C)[cite: 1]
   0x401c34:    xor    edi,ebx                             ; B XOR (A OR NOT C)[cite: 1]
   0x401c36:    lea    edx,[edi+edx*1+0x432aff97]          ; Add constant K[49][cite: 1]
   0x401c3d:    rol    edx,0xa                             ; Bitwise circular shift of 10 bits[cite: 1]
   0x401c40:    add    edx,eax                             ; Accumulate into D[cite: 1]
   0x401c42:    mov    edi,ebx                             ; MD5 Operation Round 4, step 3[cite: 1]
   0x401c44:    add    ecx,DWORD PTR [esi+0x38]             ; Add M[14][cite: 1]
   0x401c47:    not    edi                                 ; NOT B[cite: 1]
   0x401c49:    or     edi,edx                             ; D OR (NOT B)[cite: 1]
   0x401c4b:    xor    edi,eax                             ; A XOR (D OR NOT B)[cite: 1]
   0x401c4d:    lea    ecx,[edi+ecx*1-0x546bdc59]          ; Add constant K[50][cite: 1]
   0x401c54:    rol    ecx,0xf                             ; Bitwise circular shift of 15 bits[cite: 1]
   0x401c57:    add    ecx,edx                             ; Accumulate into C[cite: 1]
   0x401c59:    mov    edi,eax                             ; MD5 Operation Round 4, step 4[cite: 1]
   0x401c5b:    add    ebx,DWORD PTR [esi+0x14]             ; Add M[5][cite: 1]
   0x401c5e:    not    edi                                 ; NOT A[cite: 1]
   0x401c60:    or     edi,ecx                             ; C OR (NOT A)[cite: 1]
   0x401c62:    xor    edi,edx                             ; D XOR (C OR NOT A)[cite: 1]
   0x401c64:    lea    ebx,[edi+ebx*1-0x36c5fc7]           ; Add constant K[51][cite: 1]
   0x401c6b:    rol    ebx,0x15                            ; Bitwise circular shift of 21 bits[cite: 1]
   0x401c6e:    add    ebx,ecx                             ; Accumulate into B[cite: 1]
   0x401c70:    mov    edi,edx                             ; MD5 Operation Round 4, step 5[cite: 1]
   0x401c72:    add    eax,DWORD PTR [esi+0x30]             ; Add M[12][cite: 1]
   0x401c75:    not    edi                                 ; NOT D[cite: 1]
   0x401c77:    or     edi,ebx                             ; B OR (NOT D)[cite: 1]
   0x401c79:    xor    edi,ecx                             ; C XOR (B OR NOT D)[cite: 1]
   0x401c7b:    lea    eax,[edi+eax*1+0x655b59c3]          ; Add constant K[52][cite: 1]
   0x401c82:    rol    eax,0x6                             ; Bitwise circular shift of 6 bits[cite: 1]
   0x401c85:    add    eax,ebx                             ; Accumulate[cite: 1]
   0x401c87:    mov    edi,ecx                             ; MD5 Operation Round 4, step 6[cite: 1]
   0x401c89:    add    edx,DWORD PTR [esi+0xc]              ; Add M[3][cite: 1]
   0x401c8c:    not    edi                                 ; NOT C[cite: 1]
   0x401c8e:    or     edi,eax                             ; A OR (NOT C)[cite: 1]
   0x401c90:    xor    edi,ebx                             ; B XOR (A OR NOT C)[cite: 1]
   0x401c92:    lea    edx,[edi+edx*1-0x70f3336e]          ; Add constant K[53][cite: 1]
   0x401c99:    rol    edx,0xa                             ; Bitwise circular shift of 10 bits[cite: 1]
   0x401c9c:    add    edx,eax                             ; Accumulate[cite: 1]
   0x401c9e:    mov    edi,ebx                             ; MD5 Operation Round 4, step 7[cite: 1]
   0x401ca0:    add    ecx,DWORD PTR [esi+0x28]             ; Add M[10][cite: 1]
   0x401ca3:    not    edi                                 ; NOT B[cite: 1]
   0x401ca5:    or     edi,edx                             ; D OR (NOT B)[cite: 1]
   0x401ca7:    xor    edi,eax                             ; A XOR (D OR NOT B)[cite: 1]
   0x401ca9:    lea    ecx,[edi+ecx*1-0x100b83]            ; Add constant K[54][cite: 1]
   0x401cb0:    rol    ecx,0xf                             ; Bitwise circular shift of 15 bits[cite: 1]
   0x401cb3:    add    ecx,edx                             ; Accumulate[cite: 1]
   0x401cb5:    mov    edi,eax                             ; MD5 Operation Round 4, step 8[cite: 1]
   0x401cb7:    add    ebx,DWORD PTR [esi+0x4]              ; Add M[1][cite: 1]
   0x401cba:    not    edi                                 ; NOT A[cite: 1]
   0x401cbc:    or     edi,ecx                             ; C OR (NOT A)[cite: 1]
   0x401cbe:    xor    edi,edx                             ; D XOR (C OR NOT A)[cite: 1]
   0x401cc0:    lea    ebx,[edi+ebx*1-0x7a7ba22f]          ; Add constant K[55][cite: 1]
   0x401cc7:    rol    ebx,0x15                            ; Bitwise circular shift of 21 bits[cite: 1]
   0x401cca:    add    ebx,ecx                             ; Accumulate[cite: 1]
   0x401ccc:    mov    edi,edx                             ; MD5 Operation Round 4, step 9[cite: 1]
   0x401cce:    add    eax,DWORD PTR [esi+0x20]             ; Add M[8][cite: 1]
   0x401cd1:    not    edi                                 ; NOT D[cite: 1]
   0x401cd3:    or     edi,ebx                             ; B OR (NOT D)[cite: 1]
   0x401cd5:    xor    edi,ecx                             ; C XOR (B OR NOT D)[cite: 1]
   0x401cd7:    lea    eax,[edi+eax*1+0x6fa87e4f]          ; Add constant K[56][cite: 1]
   0x401cde:    rol    eax,0x6                             ; Bitwise circular shift of 6 bits[cite: 1]
   0x401ce1:    add    eax,ebx                             ; Accumulate[cite: 1]
   0x401ce3:    mov    edi,ecx                             ; MD5 Operation Round 4, step 10[cite: 1]
   0x401ce5:    add    edx,DWORD PTR [esi+0x3c]             ; Add M[15][cite: 1]
   0x401ce8:    not    edi                                 ; NOT C[cite: 1]
   0x401cea:    or     edi,eax                             ; A OR (NOT C)[cite: 1]
   0x401cec:    xor    edi,ebx                             ; B XOR (A OR NOT C)[cite: 1]
   0x401cee:    lea    edx,[edi+edx*1-0x1d31920]           ; Add constant K[57][cite: 1]
   0x401cf5:    rol    edx,0xa                             ; Bitwise circular shift of 10 bits[cite: 1]
   0x401cf8:    add    edx,eax                             ; Accumulate[cite: 1]
   0x401cfa:    mov    edi,ebx                             ; MD5 Operation Round 4, step 11[cite: 1]
   0x401cfc:    add    ecx,DWORD PTR [esi+0x18]             ; Add M[6][cite: 1]
   0x401cff:    not    edi                                 ; NOT B[cite: 1]
   0x401d01:    or     edi,edx                             ; D OR (NOT B)[cite: 1]
   0x401d03:    xor    edi,eax                             ; A XOR (D OR NOT B)[cite: 1]
   0x401d05:    lea    ecx,[edi+ecx*1-0x5cfebcec]          ; Add constant K[58][cite: 1]
   0x401d0c:    rol    ecx,0xf                             ; Bitwise circular shift of 15 bits[cite: 1]
   0x401d0f:    add    ecx,edx                             ; Accumulate[cite: 1]
   0x401d11:    mov    edi,eax                             ; MD5 Operation Round 4, step 12[cite: 1]
   0x401d13:    add    ebx,DWORD PTR [esi+0x34]             ; Add M[13][cite: 1]
   0x401d16:    not    edi                                 ; NOT A[cite: 1]
   0x401d18:    or     edi,ecx                             ; C OR (NOT A)[cite: 1]
   0x401d1a:    xor    edi,edx                             ; D XOR (C OR NOT A)[cite: 1]
   0x401d1c:    lea    ebx,[edi+ebx*1+0x4e0811a1]          ; Add constant K[59][cite: 1]
   0x401d23:    rol    ebx,0x15                            ; Bitwise circular shift of 21 bits[cite: 1]
   0x401d26:    add    ebx,ecx                             ; Accumulate[cite: 1]
   0x401d28:    mov    edi,edx                             ; MD5 Operation Round 4, step 13[cite: 1]
   0x401d2a:    add    eax,DWORD PTR [esi+0x10]             ; Add M[4][cite: 1]
   0x401d2d:    not    edi                                 ; NOT D[cite: 1]
   0x401d2f:    or     edi,ebx                             ; B OR (NOT D)[cite: 1]
   0x401d31:    xor    edi,ecx                             ; C XOR (B OR NOT D)[cite: 1]
   0x401d33:    lea    eax,[edi+eax*1-0x8ac817e]           ; Add constant K[60][cite: 1]
   0x401d3a:    rol    eax,0x6                             ; Bitwise circular shift of 6 bits[cite: 1]
   0x401d3d:    add    eax,ebx                             ; Accumulate[cite: 1]
   0x401d3f:    mov    edi,ecx                             ; MD5 Operation Round 4, step 14[cite: 1]
   0x401d41:    add    edx,DWORD PTR [esi+0x2c]             ; Add M[11][cite: 1]
   0x401d44:    not    edi                                 ; NOT C[cite: 1]
   0x401d46:    or     edi,eax                             ; A OR (NOT C)[cite: 1]
   0x401d48:    xor    edi,ebx                             ; B XOR (A OR NOT C)[cite: 1]
   0x401d4a:    lea    edx,[edi+edx*1-0x42c50dcb]          ; Add constant K[61][cite: 1]
   0x401d51:    rol    edx,0xa                             ; Bitwise circular shift of 10 bits[cite: 1]
   0x401d54:    add    edx,eax                             ; Accumulate[cite: 1]
   0x401d56:    mov    edi,ebx                             ; MD5 Operation Round 4, step 15[cite: 1]
   0x401d58:    add    ecx,DWORD PTR [esi+0x8]              ; Add M[2][cite: 1]
   0x401d5b:    not    edi                                 ; NOT B[cite: 1]
   0x401d5d:    or     edi,edx                             ; D OR (NOT B)[cite: 1]
   0x401d5f:    xor    edi,eax                             ; A XOR (D OR NOT B)[cite: 1]
   0x401d61:    lea    ecx,[edi+ecx*1+0x2ad7d2bb]          ; Add constant K[62][cite: 1]
   0x401d68:    rol    ecx,0xf                             ; Bitwise circular shift of 15 bits[cite: 1]
   0x401d6b:    add    ecx,edx                             ; Accumulate[cite: 1]
   0x401d6d:    mov    edi,eax                             ; MD5 Operation Round 4, step 16[cite: 1]
   0x401d6f:    add    ebx,DWORD PTR [esi+0x24]             ; Add M[9][cite: 1]
   0x401d72:    not    edi                                 ; NOT A[cite: 1]
   0x401d74:    or     edi,ecx                             ; C OR (NOT A)[cite: 1]
   0x401d76:    xor    edi,edx                             ; D XOR (C OR NOT A)[cite: 1]
   0x401d78:    lea    ebx,[edi+ebx*1-0x14792c6f]          ; Add constant K[63][cite: 1]
   0x401d7f:    rol    ebx,0x15                            ; Bitwise circular shift of 21 bits[cite: 1]
   0x401d82:    add    ebx,ecx                             ; End of the 4 MD5 rounds[cite: 1]
   0x401d84:    add    DWORD PTR ds:0x404270,eax           ; Update accumulator state A[cite: 1]
   0x401d8a:    add    DWORD PTR ds:0x404274,ebx           ; Update accumulator state B[cite: 1]
   0x401d90:    add    DWORD PTR ds:0x404278,ecx           ; Update accumulator state C[cite: 1]
   0x401d96:    add    DWORD PTR ds:0x40427c,edx           ; Update accumulator state D[cite: 1]
   0x401d9c:    sub    DWORD PTR ds:0x404284,0x40          ; Decrement remaining size by 64 bytes[cite: 1]
   0x401da3:    add    esi,0x40                            ; Advance source pointer by 64 bytes[cite: 1]
   0x401da6:    jmp    0x401744                            ; Process next 64-byte block[cite: 1]
   0x401dab:    cmp    BYTE PTR ds:0x404288,0x0             ; Test if padding has already been applied[cite: 1]
   0x401db2:    je     0x401e10                            ; If yes, jump to fingerprint finalization[cite: 1]
   0x401db4:    mov    ecx,DWORD PTR ds:0x404284           ; Load remaining bytes of the last block[cite: 1]
   0x401dba:    mov    BYTE PTR ds:0x404288,0x0             ; Mark padding as in-progress/done[cite: 1]
   0x401dc1:    mov    DWORD PTR ds:0x404284,0x40          ; Set next processing size to 64 bytes[cite: 1]
   0x401dcb:    mov    eax,ecx                             ; Save remaining size in EAX[cite: 1]
   0x401dcd:    mov    edi,0x40428c                        ; Pointer to temporary padding buffer[cite: 1]
   0x401dd2:    test   eax,eax                             ; Are there unprocessed bytes remaining?[cite: 1]
   0x401dd4:    je     0x401dd8                            ; If not, skip copy[cite: 1]
   0x401dd6:    rep movs BYTE PTR es:[edi],BYTE PTR ds:[esi]; Copy remaining bytes into buffer[cite: 1]
   0x401dd8:    mov    ecx,eax                             ; Size restored in ECX[cite: 1]
   0x401dda:    mov    BYTE PTR [edi],0x80                 ; Append termination bit 0x80 to end of message[cite: 1]
   0x401ddd:    sub    ecx,0x37                            ; Calculate required space for size (56 bytes)[cite: 1]
   0x401de0:    inc    edi                                 ; Advance EDI past 0x80 byte[cite: 1]
   0x401de1:    neg    ecx                                 ; Invert to determine required number of zeros[cite: 1]
   0x401de3:    je     0x401df5                            ; If perfectly aligned, jump to size storage[cite: 1]
   0x401de5:    jns    0x401df1                            ; If positive, current block is sufficient[cite: 1]
   0x401de7:    add    DWORD PTR ds:0x404284,0x40          ; Otherwise, add a second padding block (64 bytes)[cite: 1]
   0x401dee:    add    ecx,0x40                            ; Adjust zero counter[cite: 1]
   0x401df1:    xor    al,al                               ; Prepare null byte (0x00)[cite: 1]
   0x401df3:    rep stos BYTE PTR es:[edi],al              ; Fill buffer with 0x00 bytes[cite: 1]
   0x401df5:    mov    edx,0x8                             ; Multiplier 8 to convert bytes to bits[cite: 1]
   0x401dfa:    mov    eax,ds:0x404280                     ; Retrieve initial message size[cite: 1]
   0x401dff:    mul    edx                                 ; EDX:EAX = size in bits[cite: 1]
   0x401e01:    mov    DWORD PTR [edi],eax                 ; Store low-order 32 bits of size[cite: 1]
   0x401e03:    mov    DWORD PTR [edi+0x4],edx             ; Store high-order 32 bits of size[cite: 1]
   0x401e06:    mov    esi,0x40428c                        ; ESI now points to prepared padding block[cite: 1]
   0x401e0b:    jmp    0x401744                            ; Execute last MD5 pass on this block[cite: 1]
   0x401e10:    mov    esi,0x404270                        ; Pointer to final hash (A, B, C, D)[cite: 1]
   0x401e15:    mov    edi,DWORD PTR [esp+0x24]            ; Retrieve destination buffer for result[cite: 1]
   0x401e19:    push   esi                                 ; Save source address on stack[cite: 1]
   0x401e1a:    mov    ecx,0x4                             ; 4 dwords = 16 bytes = 128 bits of MD5 hash[cite: 1]
   0x401e1f:    rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi]; Copy final MD5 hash to destination[cite: 1]
   0x401e21:    pop    edi                                 ; Restore pointer[cite: 1]
   0x401e22:    mov    ecx,0x27                            ; Size for clearing memory area[cite: 1]
   0x401e27:    xor    eax,eax                             ; Zero internal registers[cite: 1]
   0x401e29:    rep stos DWORD PTR es:[edi],eax              ; Wipe sensitive data from MD5 context[cite: 1]
   0x401e2b:    popa                                       ; Restore all general-purpose registers[cite: 1]
   0x401e2c:    ret    0xc                                 ; Return and pop 12 bytes of parameters[cite: 1]
   0x401e2f:    int3                                       ; Alignment / Padding NOP instruction[cite: 1]
   0x401e30:    pusha                                      ; Entry point for ECC point analysis/validation function[cite: 1]
   0x401e31:    mov    esi,DWORD PTR [esp+0x24]            ; Pointer to first ECC point (Point P)[cite: 1]
   0x401e35:    mov    edi,DWORD PTR [esp+0x28]            ; Pointer to second ECC point (Point Q)[cite: 1]
   0x401e39:    mov    ebp,DWORD PTR ds:0x40409c           ; Load finite field modulo p[cite: 1]
   0x401e3f:    mov    eax,DWORD PTR [esi]                 ; Test if point P is point at infinity[cite: 1]
   0x401e41:    test   eax,eax                             ; Validate point P presence flag[cite: 1]
   0x401e43:    je     0x401f61                            ; If invalid/null, exit[cite: 1]
   0x401e49:    mov    eax,DWORD PTR [edi]                 ; Test if point Q is point at infinity[cite: 1]
   0x401e4b:    test   eax,eax                             ; Validate point Q presence flag[cite: 1]
   0x401e4d:    je     0x401f6a                            ; If Q is null, copy P to Q and terminate[cite: 1]
   0x401e53:    mov    eax,DWORD PTR [esi+0x4]              ; EAX = P.x (X coordinate of point P)[cite: 1]
   0x401e56:    mov    ecx,DWORD PTR [esi+0x8]              ; ECX = P.y (Y coordinate of point P)[cite: 1]
   0x401e59:    mov    edx,DWORD PTR [esi+0xc]              ; EDX = P.z (Z coordinate of point P)[cite: 1]
   0x401e5c:    cmp    eax,DWORD PTR [edi+0x4]              ; Compare P.x with Q.x[cite: 1]
   0x401e5f:    jne    0x401ea6                            ; If X1 != X2, jump to general point addition[cite: 1]
   0x401e61:    cmp    ecx,DWORD PTR [edi+0x8]              ; Compare P.y with Q.y[cite: 1]
   0x401e64:    jne    0x401ea6                            ; If Y1 != Y2, jump to addition[cite: 1]
   0x401e66:    cmp    edx,DWORD PTR [edi+0xc]              ; Compare P.z with Q.z[cite: 1]
   0x401e69:    jne    0x401ea6                            ; If Z1 != Z2, jump to addition[cite: 1]
   0x401e6b:    mov    eax,DWORD PTR [esi+0x10]             ; Load additional component P.x2[cite: 1]
   0x401e6e:    mov    ecx,DWORD PTR [esi+0x14]             ; Load additional component P.y2[cite: 1]
   0x401e71:    mov    edx,DWORD PTR [esi+0x18]             ; Load additional component P.z2[cite: 1]
   0x401e74:    cmp    eax,DWORD PTR [edi+0x10]             ; Compare with Q.x2[cite: 1]
   0x401e77:    jne    0x401e87                            ; Symmetry test / inverse point test[cite: 1]
   0x401e79:    cmp    ecx,DWORD PTR [edi+0x14]             ; Compare with Q.y2[cite: 1]
   0x401e7c:    jne    0x401e87                            ; Symmetry test[cite: 1]
   0x401e7e:    cmp    edx,DWORD PTR [edi+0x18]             ; Compare with Q.z2[cite: 1]
   0x401e81:    je     0x401f94                            ; If P == Q, ECC point doubling[cite: 1]
   0x401e87:    mov    ebx,ebp                             ; EBX = modulo p[cite: 1]
   0x401e89:    sub    ebx,DWORD PTR [edi+0x10]             ; EBX = p - Q.x2[cite: 1]
   0x401e8c:    cmp    ebx,eax                             ; Test if P.x2 == -Q.x2 mod p[cite: 1]
   0x401e8e:    jne    0x401ea6                            ; If not, standard geometric addition[cite: 1]
   0x401e90:    mov    ebx,ebp                             ; EBX = modulo p[cite: 1]
   0x401e92:    sub    ebx,DWORD PTR [edi+0x14]             ; EBX = p - Q.y2[cite: 1]
   0x401e95:    cmp    ebx,ecx                             ; Test if P.y2 == -Q.y2 mod p[cite: 1]
   0x401e97:    jne    0x401ea6                            ; If not, standard geometric addition[cite: 1]
   0x401e99:    mov    ebx,ebp                             ; EBX = modulo p[cite: 1]
   0x401e9b:    sub    ebx,DWORD PTR [edi+0x18]             ; EBX = p - Q.z2[cite: 1]
   0x401e9e:    cmp    ebx,edx                             ; Test if P.z2 == -Q.z2 mod p[cite: 1]
   0x401ea0:    je     0x401f65                            ; If P == -Q, result is point at infinity (0)[cite: 1]
   0x401ea6:    add    esi,0x4                             ; ESI advances to coordinates P[cite: 1]
   0x401ea9:    add    edi,0x4                             ; EDI advances to coordinates Q[cite: 1]
   0x401eac:    mov    ebx,0x404320                        ; Temporary buffer for ECC computations[cite: 1]
   0x401eb1:    xchg   edi,esi                             ; Exchange point pointers[cite: 1]
   0x401eb3:    call   0x402267                            ; Modular subtraction: EBX = P - Q mod p[cite: 1]
   0x401eb8:    add    edi,0xc                             ; Advance to next field in ECC structure[cite: 1]
   0x401ebb:    add    esi,0xc                             ; Advance to next field[cite: 1]
   0x401ebe:    sub    ebx,0x10                            ; Adjust temporary buffer pointer[cite: 1]
   0x401ec1:    call   0x402267                            ; Modular subtraction on subsequent components[cite: 1]
   0x401ec6:    lea    esi,[ebx+0x10]                      ; ESI points to intermediate result[cite: 1]
   0x401ec9:    add    ebx,0x20                            ; Allocate space in temporary buffer[cite: 1]
   0x401ecc:    call   0x402339                            ; Multiply and reduce modularly per curve constants[cite: 1]
   0x401ed1:    lea    esi,[ebx-0x20]                      ; Step back source address[cite: 1]
   0x401ed4:    mov    edi,ebx                             ; EDI = workspace area[cite: 1]
   0x401ed6:    add    ebx,0x10                            ; Advance destination pointer[cite: 1]
   0x401ed9:    call   0x402292                            ; Full modular multiplication: ESI * EDI mod p[cite: 1]
   0x401ede:    mov    esi,ebx                             ; Load intermediate product[cite: 1]
   0x401ee0:    mov    edi,ebx                             ; Source = Destination (Modular squaring)[cite: 1]
   0x401ee2:    add    ebx,0x10                            ; Advance buffer[cite: 1]
   0x401ee5:    call   0x402292                            ; Calculate power / modular squaring[cite: 1]
   0x401eea:    mov    edi,DWORD PTR [esp+0x24]            ; Restore pointer P[cite: 1]
   0x401eee:    mov    esi,ebx                             ; ESI = temporary result[cite: 1]
   0x401ef0:    add    edi,0x4                             ; Alignment on P.x[cite: 1]
   0x401ef3:    sub    ebx,0x20                            ; Reposition EBX[cite: 1]
   0x401ef6:    call   0x402267                            ; Modular subtraction to obtain new X3 coordinate[cite: 1]
   0x401efb:    mov    eax,DWORD PTR [edi]                 ; Load result X3[cite: 1]
   0x401efd:    mov    ecx,DWORD PTR [edi+0x4]              ; Load component Y3[cite: 1]
   0x401f00:    mov    edx,DWORD PTR [edi+0x8]              ; Load component Z3[cite: 1]
   0x401f03:    mov    DWORD PTR [ebx+0x20],eax            ; Store X3 in destination point[cite: 1]
   0x401f06:    mov    DWORD PTR [ebx+0x24],ecx            ; Store Y3 in destination point[cite: 1]
   0x401f09:    mov    DWORD PTR [ebx+0x28],edx            ; Store Z3 in destination point[cite: 1]
   0x401f0c:    mov    edi,DWORD PTR [esp+0x28]            ; Load point Q[cite: 1]
   0x401f10:    mov    esi,ebx                             ; Load current buffer[cite: 1]
   0x401f12:    add    edi,0x4                             ; Align on Q.x[cite: 1]
   0x401f15:    call   0x402267                            ; Calculate difference for Y3 coordinate[cite: 1]
   0x401f1a:    mov    edi,ebx                             ; EDI points to intermediate result[cite: 1]
   0x401f1c:    lea    esi,[ebx+0x20]                      ; ESI points to intermediate point[cite: 1]
   0x401f1f:    mov    ebx,esi                             ; Update EBX[cite: 1]
   0x401f21:    call   0x402267                            ; Finalize curve addition formula[cite: 1]
   0x401f26:    mov    esi,ebx                             ; ESI = computed point[cite: 1]
   0x401f28:    lea    edi,[ebx-0x10]                      ; EDI = temporary target[cite: 1]
   0x401f2b:    sub    ebx,0x30                            ; Step back EBX in work stack[cite: 1]
   0x401f2e:    call   0x402292                            ; Final multiplication of projective coordinates[cite: 1]
   0x401f33:    mov    esi,ebx                             ; ESI = sum coordinates[cite: 1]
   0x401f35:    mov    edi,DWORD PTR [esp+0x24]            ; Restore first parameter P[cite: 1]
   0x401f39:    mov    ebx,DWORD PTR [esp+0x28]            ; Restore second parameter Q (destination)[cite: 1]
   0x401f3d:    add    edi,0x10                            ; Pointer to second half of point P[cite: 1]
   0x401f40:    add    ebx,0x10                            ; Pointer to second half of point Q[cite: 1]
   0x401f43:    call   0x402267                            ; Final adjustment mod p[cite: 1]
   0x401f48:    mov    eax,DWORD PTR [esi+0x10]             ; Load final projective component X[cite: 1]
   0x401f4b:    mov    ecx,DWORD PTR [esi+0x14]             ; Load final projective component Y[cite: 1]
   0x401f4e:    mov    edx,DWORD PTR [esi+0x18]             ; Load final projective component Z[cite: 1]
   0x401f51:    mov    DWORD PTR [ebx-0x10],0x1             ; Mark receptacle point as valid (non-infinity)[cite: 1]
   0x401f58:    mov    DWORD PTR [ebx-0xc],eax             ; Store resulting X coordinate[cite: 1]
   0x401f5b:    mov    DWORD PTR [ebx-0x8],ecx             ; Store resulting Y coordinate[cite: 1]
   0x401f5e:    mov    DWORD PTR [ebx-0x4],edx             ; Store resulting Z coordinate[cite: 1]
   0x401f61:    popa                                       ; Restore registers[cite: 1]
   0x401f62:    ret    0x8                                 ; Return from ECC point addition[cite: 1]
   0x401f65:    and    DWORD PTR [edi],0x0                 ; Set resulting point to point at infinity (P + (-P) = 0)[cite: 1]
   0x401f68:    jmp    0x401f61                            ; End[cite: 1]
   0x401f6a:    mov    eax,DWORD PTR [esi]                 ; Copy P to Q (case Q = 0): load flag[cite: 1]
   0x401f6c:    mov    ebx,DWORD PTR [esi+0x4]              ; Load P.x[cite: 1]
   0x401f6f:    mov    ecx,DWORD PTR [esi+0x8]              ; Load P.y[cite: 1]
   0x401f72:    mov    edx,DWORD PTR [esi+0xc]              ; Load P.z[cite: 1]
   0x401f75:    mov    DWORD PTR [edi],eax                 ; Copy flag to Q[cite: 1]
   0x401f77:    mov    DWORD PTR [edi+0x4],ebx             ; Copy Q.x = P.x[cite: 1]
   0x401f7a:    mov    DWORD PTR [edi+0x8],ecx             ; Copy Q.y = P.y[cite: 1]
   0x401f7d:    mov    DWORD PTR [edi+0xc],edx             ; Copy Q.z = P.z[cite: 1]
   0x401f80:    mov    ebx,DWORD PTR [esi+0x10]             ; Load P.x2[cite: 1]
   0x401f83:    mov    ecx,DWORD PTR [esi+0x14]             ; Load P.y2[cite: 1]
   0x401f86:    mov    edx,DWORD PTR [esi+0x18]             ; Load P.z2[cite: 1]
   0x401f89:    mov    DWORD PTR [edi+0x10],ebx             ; Copy Q.x2 = P.x2[cite: 1]
   0x401f8c:    mov    DWORD PTR [edi+0x14],ecx             ; Copy Q.y2 = P.y2[cite: 1]
   0x401f8f:    mov    DWORD PTR [edi+0x18],edx             ; Copy Q.z2 = P.z2[cite: 1]
   0x401f92:    jmp    0x401f61                            ; End copy[cite: 1]
   0x401f94:    push   edi                                 ; Empirical point doubling (P == Q): push point Q[cite: 1]
   0x401f95:    push   esi                                 ; Push point P[cite: 1]
   0x401f96:    call   0x401f9d                            ; Call point doubling routine [2]P[cite: 1]
   0x401f9b:    jmp    0x401f61                            ; End[cite: 1]
   0x401f9d:    pusha                                      ; ECC point doubling routine [2]P[cite: 1]
   0x401f9e:    mov    esi,DWORD PTR [esp+0x24]            ; Load point P[cite: 1]
   0x402082:    and    DWORD PTR [edi],0x0                 ; Point at infinity in case of error/null point[cite: 1]
   0x402085:    jmp    0x40207e                            ; Exit[cite: 1]
   0x402087:    pusha                                      ; Coordinate conversion / projection routine[cite: 1]
   0x402088:    mov    esi,DWORD PTR [esp+0x24]            ; Pointer to source point[cite: 1]
   0x40208c:    xor    ecx,ecx                             ; ECX = 0 (Carry accumulator)[cite: 1]
   0x40208e:    add    esi,0x4                             ; Advance to X coordinate[cite: 1]
   0x402091:    xor    ebp,ebp                             ; EBP = 0 (High-order product)[cite: 1]
   0x402093:    mov    eax,DWORD PTR [esi]                 ; EAX = X.part1[cite: 1]
   0x402095:    mul    DWORD PTR ds:0x40409c               ; Multiply by field constant (p)[cite: 1]
   0x40209b:    add    eax,DWORD PTR [esi+0x4]              ; Add X.part2 to low product[cite: 1]
   0x40209e:    adc    ecx,edx                             ; Propagate carry into ECX[cite: 1]
   0x4020a0:    mul    DWORD PTR ds:0x40409c               ; Multiply again by modulo p[cite: 1]
   0x4020a6:    mov    edi,eax                             ; EDI = low-order temporary result[cite: 1]
   0x4020a8:    mov    ebx,edx                             ; EBX = high-order temporary result[cite: 1]
   0x4020aa:    mov    eax,ecx                             ; EAX = accumulated carry[cite: 1]
   0x4020ac:    mul    DWORD PTR ds:0x40409c               ; Multiply carry by p[cite: 1]
   0x4020b2:    add    eax,ebx                             ; Combine partial results[cite: 1]
   0x4020b4:    adc    ebp,edx                             ; Accumulate into EBP with carry[cite: 1]
   0x4020b6:    add    edi,DWORD PTR [esi+0x8]              ; Add X.part3[cite: 1]
   0x4020b9:    adc    eax,0x0                             ; Propagate carry[cite: 1]
   0x4020bc:    adc    ebp,0x0                             ; Propagate carry to EBP[cite: 1]
   0x4020bf:    mov    esi,DWORD PTR [esp+0x28]            ; Destination pointer[cite: 1]
   0x4020c3:    mov    DWORD PTR [esi],edi                 ; Store dword 0 of projected point[cite: 1]
   0x4020c5:    mov    DWORD PTR [esi+0x4],eax             ; Store dword 1[cite: 1]
   0x4020c8:    mov    DWORD PTR [esi+0x8],ebp             ; Store dword 2[cite: 1]
   0x4020cb:    and    DWORD PTR [esi+0xc],0x0             ; Zero out high-order dword (padding/sign)[cite: 1]
   0x4020cf:    popa                                       ; Restore registers[cite: 1]
   0x4020d0:    ret    0x8                                 ; Return from projection[cite: 1]
   0x4020d3:    int3                                       ; Alignment / Padding NOP instruction[cite: 1]




   0x402180:    pusha                                      ; 64-bit x 64-bit -> 128-bit multiplication routine[cite: 1]
   0x402181:    mov    esi,DWORD PTR [esp+0x24]            ; Operand A (64 bits: [ESI+4]:[ESI])[cite: 1]
   0x402185:    mov    edi,DWORD PTR [esp+0x28]            ; Operand B (64 bits: [EDI+4]:[EDI])[cite: 1]
   0x402189:    mov    eax,DWORD PTR [esi]                 ; EAX = A.low[cite: 1]
   0x40218b:    mul    DWORD PTR [edi]                     ; EDX:EAX = A.low * B.low[cite: 1]
   0x40218d:    mov    ebx,eax                             ; EBX = R0 (lowest 32 bits)[cite: 1]
   0x40218f:    mov    ebp,edx                             ; EBP = Intermediate carry[cite: 1]
   0x402191:    xor    ecx,ecx                             ; ECX = 0 (High-order accumulator)[cite: 1]
   0x402193:    mov    eax,DWORD PTR [esi]                 ; EAX = A.low[cite: 1]
   0x402195:    mul    DWORD PTR [edi+0x4]                 ; EDX:EAX = A.low * B.high[cite: 1]
   0x402198:    add    ebp,eax                             ; Accumulate into dword 1[cite: 1]
   0x40219a:    adc    ecx,edx                             ; Propagate carry to dword 2[cite: 1]
   0x40219c:    mov    eax,DWORD PTR [esi+0x4]              ; EAX = A.high[cite: 1]
   0x40219f:    mul    DWORD PTR [edi]                     ; EDX:EAX = A.high * B.low[cite: 1]
   0x4021a1:    add    ebp,eax                             ; Accumulate into dword 1[cite: 1]
   0x4021a3:    adc    ecx,edx                             ; Propagate carry to dword 2[cite: 1]
   0x4021a5:    mov    eax,DWORD PTR [esp+0x2c]            ; Destination pointer (128 bits)[cite: 1]
   0x4021a9:    mov    DWORD PTR [eax],ebx                 ; Save dword 0 (R0)[cite: 1]
   0x4021ab:    mov    ebx,ebp                             ; EBX = R1 (dword 1)[cite: 1]
   0x4021ad:    mov    eax,DWORD PTR [esi+0x4]              ; EAX = A.high[cite: 1]
   0x4021b0:    adc    ebp,ebp                             ; Save carry flag[cite: 1]
   0x4021b2:    mul    DWORD PTR [edi+0x4]                 ; EDX:EAX = A.high * B.high[cite: 1]
   0x4021b5:    and    ebp,0x1                             ; Extract carry bit[cite: 1]
   0x4021b8:    add    ecx,eax                             ; Accumulate into dword 2[cite: 1]
   0x4021ba:    adc    ebp,edx                             ; Accumulate into dword 3 (R3)[cite: 1]
   0x4021bc:    mov    eax,DWORD PTR [esp+0x2c]            ; Destination[cite: 1]
   0x4021c0:    mov    DWORD PTR [eax+0x4],ebx             ; Save dword 1 (R1)[cite: 1]
   0x4021c3:    mov    DWORD PTR [eax+0x8],ecx             ; Save dword 2 (R2)[cite: 1]
   0x4021c6:    mov    DWORD PTR [eax+0xc],ebp             ; Save dword 3 (R3)[cite: 1]
   0x4021c9:    popa                                       ; Restore registers[cite: 1]
   0x4021ca:    ret    0xc                                 ; End of 64x64->128 multiplication[cite: 1]




   0x4021cd:    pusha                                      ; 128-bit mod p modular reduction routine[cite: 1]
   0x4021ce:    mov    esi,DWORD PTR [esp+0x24]            ; Pointer to 128-bit number to reduce[cite: 1]
   0x4021d2:    mov    edi,0x404360                        ; Temporary computation buffer[cite: 1]
   0x4021d7:    mov    ecx,DWORD PTR [esi]                 ; Load dword 0[cite: 1]
   0x4021d9:    mov    edx,DWORD PTR [esi+0x4]              ; Load dword 1[cite: 1]
   0x4021dc:    xor    ebx,ebx                             ; EBX = 0 (dword 2 accumulator)[cite: 1]
   0x4021de:    mov    eax,DWORD PTR [esi+0x8]              ; Load dword 2[cite: 1]
   0x4021e1:    or     eax,DWORD PTR [esi+0xc]              ; Test if high part (dwords 2 and 3) is zero[cite: 1]
   0x4021e4:    je     0x402201                            ; If high part is zero, proceed to final subtraction[cite: 1]
   0x4021e6:    lea    eax,[esi+0x8]                       ; EAX points to high part[cite: 1]
   0x4021e9:    push   edi                                 ; Product destination[cite: 1]
   0x4021ea:    push   0x4040e0                            ; Reduction constant (2^64 mod p)[cite: 1]
   0x4021ef:    push   eax                                 ; High part[cite: 1]
   0x4021f0:    call   0x402180                            ; Multiply high part by (2^64 mod p)[cite: 1]
   0x4021f5:    add    ecx,DWORD PTR [edi]                 ; Re-inject product result into dword 0[cite: 1]
   0x4021f7:    adc    edx,DWORD PTR [edi+0x4]              ; Re-inject with carry into dword 1[cite: 1]
   0x4021fa:    adc    ebx,0x0                             ; Accumulate global carry[cite: 1]
   0x4021fd:    mov    esi,edi                             ; Reduction loop[cite: 1]
   0x4021ff:    jmp    0x4021de                            ; Re-evaluate if high part is zero[cite: 1]
   0x402201:    sub    ecx,DWORD PTR ds:0x40403c           ; Subtract low part of modulo p[cite: 1]
   0x402207:    sbb    edx,DWORD PTR ds:0x404040           ; Subtract high part of modulo p with borrow[cite: 1]
   0x40220d:    sbb    ebx,0x0                             ; Subtract global borrow[cite: 1]
   0x402210:    jae    0x402201                            ; As long as result >= p, continue subtracting p[cite: 1]
   0x402212:    add    ecx,DWORD PTR ds:0x40403c           ; Final adjustment: add p back in case of negative underflow[cite: 1]
   0x402218:    adc    edx,DWORD PTR ds:0x404040           ; Restore exact modular value into [EDX:ECX][cite: 1]
   0x40221e:    mov    edi,DWORD PTR [esp+0x28]            ; Pointer to destination (reduced 64 bits)[cite: 1]
   0x402222:    mov    DWORD PTR [edi],ecx                 ; Store reduced dword 0[cite: 1]
   0x402224:    mov    DWORD PTR [edi+0x4],edx             ; Store reduced dword 1[cite: 1]
   0x402227:    popa                                       ; Restore registers[cite: 1]
   0x402228:    ret    0x8                                 ; End of modular reduction[cite: 1]




   0x402230:   push   eax                                 ; 3-component modular addition: [EBX] = ([ESI] + [EDI]) mod ebp
   0x402231:   push   ecx                                 ; Save ECX
   0x402232:   push   edx                                 ; Save EDX
   0x402233:   mov    eax,DWORD PTR [esi]                 ; Load component 0 of A
   0x402235:   mov    edx,DWORD PTR [esi+0x4]              ; Load component 1 of A
   0x402238:   mov    ecx,DWORD PTR [esi+0x8]              ; Load component 2 of A
   0x40223b:   add    eax,DWORD PTR [edi]                 ; A0 + B0
   0x40223d:   jb     0x402243                            ; If carry (overflow) -> requires mod p reduction
   0x40223f:   cmp    eax,ebp                             ; Compare result to modulo p (EBP)
   0x402241:   jb     0x402245                            ; If lower than p, no reduction required
   0x402243:   sub    eax,ebp                             ; Reduction: A0 = (A0 + B0) - p
   0x402245:   add    edx,DWORD PTR [edi+0x4]              ; A1 + B1
   0x402248:   jb     0x40224e                            ; If carry -> mod p reduction
   0x40224a:   cmp    edx,ebp                             ; Compare to modulo p
   0x40224c:   jb     0x402250                            ; If lower than p, continue
   0x40224e:   sub    edx,ebp                             ; Reduction: A1 = (A1 + B1) - p
   0x402250:   add    ecx,DWORD PTR [edi+0x8]              ; A2 + B2
   0x402253:   jb     0x402259                            ; If carry -> mod p reduction
   0x402255:   cmp    ecx,ebp                             ; Compare to modulo p
   0x402257:   jb     0x40225b                            ; If lower than p, continue
   0x402259:   sub    ecx,ebp                             ; Reduction: A2 = (A2 + B2) - p
   0x40225b:   mov    DWORD PTR [ebx],eax                 ; Store result R0 in EBX
   0x40225d:   mov    DWORD PTR [ebx+0x4],edx             ; Store result R1 in EBX+4
   0x402260:   mov    DWORD PTR [ebx+0x8],ecx             ; Store result R2 in EBX+8
   0x402263:   pop    edx                                 ; Restore EDX
   0x402264:   pop    ecx                                 ; Restore ECX
   0x402265:   pop    eax                                 ; Restore EAX
   0x402266:   ret                                        ; End of modular addition



   0x402267:   push   eax                                 ; 3-component modular subtraction: [EBX] = ([ESI] - [EDI]) mod ebp
   0x402268:   push   ecx                                 ; Save ECX
   0x402269:   push   edx                                 ; Save EDX
   0x40226a:   mov    eax,DWORD PTR [esi]                 ; Load A0
   0x40226c:   mov    edx,DWORD PTR [esi+0x4]              ; Load A1
   0x40226f:   mov    ecx,DWORD PTR [esi+0x8]              ; Load A2
   0x402272:   sub    eax,DWORD PTR [edi]                 ; A0 - B0
   0x402274:   jae    0x402278                            ; If no borrow (result >= 0), continue
   0x402276:   add    eax,ebp                             ; Modular compensation: if < 0, add p (EBP)
   0x402278:   sub    edx,DWORD PTR [edi+0x4]              ; A1 - B1
   0x40227b:   jae    0x40227f                            ; If >= 0, continue
   0x40227d:   add    edx,ebp                             ; Add p
   0x40227f:   sub    ecx,DWORD PTR [edi+0x8]              ; A2 - B2
   0x402282:   jae    0x402286                            ; If >= 0, continue
   0x402284:   add    ecx,ebp                             ; Add p
   0x402286:   mov    DWORD PTR [ebx],eax                 ; Write R0
   0x402288:   mov    DWORD PTR [ebx+0x4],edx             ; Write R1
   0x40228b:   mov    DWORD PTR [ebx+0x8],ecx             ; Write R2
   0x40228e:   pop    edx                                 ; Restore EDX
   0x40228f:   pop    ecx                                 ; Restore ECX
   0x402290:   pop    eax                                 ; Restore EAX
   0x402291:   ret                                        ; End of modular subtraction
   0x402292:   push   eax                                 ; Full 3-word modular multiplication: [EBX] = ([ESI] * [EDI]) mod ebp
   0x402293:   push   ecx                                 ; Save ECX
   0x402294:   push   edx                                 ; Save EDX
   0x402295:   mov    eax,DWORD PTR [esi]                 ; Load A0
   0x402297:   mul    DWORD PTR [edi+0x8]                 ; EDX:EAX = A0 * B2
   0x40229a:   div    ebp                                 ; Remainder in EDX = (A0 * B2) mod ebp
   0x40229c:   mov    ecx,edx                             ; ECX = Remainder 1
   0x40229e:   mov    eax,DWORD PTR [esi+0x4]              ; Load A1
   0x4022a1:   mul    DWORD PTR [edi+0x4]                 ; EDX:EAX = A1 * B1
   0x4022a4:   div    ebp                                 ; Remainder in EDX = (A1 * B1) mod ebp
   0x4022a6:   add    ecx,edx                             ; ECX = Remainder 1 + Remainder 2
   0x4022a8:   jb     0x4022ae                            ; Overflow -> reduction
   0x4022aa:   cmp    ecx,ebp                             ; Compare to modulo p
   0x4022ac:   jb     0x4022b0                            ; If < p, continue
   0x4022ae:   sub    ecx,ebp                             ; ECX = ECX - p
   0x4022b0:   mov    eax,DWORD PTR [esi+0x8]              ; Load A2
   0x4022b3:   mul    DWORD PTR [edi]                     ; EDX:EAX = A2 * B0
   0x4022b5:   div    ebp                                 ; Remainder in EDX
   0x4022b7:   add    ecx,edx                             ; Accumulate modular remainder
   0x4022b9:   jb     0x4022bf                            ; Overflow -> reduction
   0x4022bb:   cmp    ecx,ebp                             ; Compare to modulo p
   0x4022bd:   jb     0x4022c1                            ; If < p, continue
   0x4022bf:   sub    ecx,ebp                             ; ECX = ECX - p
   0x4022c1:   mov    DWORD PTR [ebx],ecx                 ; Write component R0 of product
   0x4022c3:   mov    eax,DWORD PTR [esi]                 ; Load A0
   0x4022c5:   mul    DWORD PTR [edi]                     ; EDX:EAX = A0 * B0
   0x4022c7:   div    ebp                                 ; Remainder in EDX
   0x4022c9:   mov    ecx,edx                             ; ECX = Remainder
   0x4022cb:   add    ecx,edx                             ; Doubling remainder
   0x4022cd:   jb     0x4022d3                            ; Overflow -> reduction
   0x4022cf:   cmp    ecx,ebp                             ; Compare to p
   0x4022d1:   jb     0x4022d5                            ; If < p, continue
   0x4022d3:   sub    ecx,ebp                             ; ECX = ECX - p
   0x4022d5:   mov    eax,DWORD PTR [esi+0x4]              ; Load A1
   0x4022d8:   mul    DWORD PTR [edi+0x8]                 ; EDX:EAX = A1 * B2
   0x4022db:   div    ebp                                 ; Remainder in EDX
   0x4022dd:   add    ecx,edx                             ; Accumulate remainder
   0x4022df:   jb     0x4022e5                            ; Overflow -> reduction
   0x4022e1:   cmp    ecx,ebp                             ; Compare to p
   0x4022e3:   jb     0x4022e7                            ; If < p, continue
   0x4022e5:   sub    ecx,ebp                             ; ECX = ECX - p
   0x4022e7:   mov    eax,DWORD PTR [esi+0x8]              ; Load A2
   0x4022ea:   mul    DWORD PTR [edi+0x4]                 ; EDX:EAX = A2 * B1
   0x4022ed:   div    ebp                                 ; Remainder in EDX
   0x4022ef:   add    ecx,edx                             ; Accumulate remainder
   0x4022f1:   jb     0x4022f7                            ; Overflow -> reduction
   0x4022f3:   cmp    ecx,ebp                             ; Compare to p
   0x4022f5:   jb     0x4022f9                            ; If < p, continue
   0x4022f7:   sub    ecx,ebp                             ; ECX = ECX - p
   0x4022f9:   mov    DWORD PTR [ebx+0x4],ecx             ; Write component R1 of product
   0x4022fc:   mov    eax,DWORD PTR [esi+0x4]              ; Load A1
   0x4022ff:   mul    DWORD PTR [edi]                     ; EDX:EAX = A1 * B0
   0x402301:   div    ebp                                 ; Remainder in EDX
   0x402303:   mov    ecx,edx                             ; ECX = Remainder
   0x402305:   mov    eax,DWORD PTR [esi]                 ; Load A0
   0x402307:   mul    DWORD PTR [edi+0x4]                 ; EDX:EAX = A0 * B1
   0x40230a:   div    ebp                                 ; Remainder in EDX
   0x40230c:   add    ecx,edx                             ; Accumulate
   0x40230e:   jb     0x402314                            ; Overflow -> reduction
   0x402310:   cmp    ecx,ebp                             ; Compare to p
   0x402312:   jb     0x402316                            ; If < p, continue
   0x402314:   sub    ecx,ebp                             ; ECX = ECX - p
   0x402316:   add    ecx,ecx                             ; Double result
   0x402318:   jb     0x40231e                            ; Overflow -> reduction
   0x40231a:   cmp    ecx,ebp                             ; Compare to p
   0x40231c:   jb     0x402320                            ; If < p, continue
   0x40231e:   sub    ecx,ebp                             ; ECX = ECX - p
   0x402320:   mov    eax,DWORD PTR [esi+0x8]              ; Load A2
   0x402323:   mul    DWORD PTR [edi+0x8]                 ; EDX:EAX = A2 * B2
   0x402326:   div    ebp                                 ; Remainder in EDX
   0x402328:   add    ecx,edx                             ; Accumulate
   0x40232a:   jb     0x402330                            ; Overflow -> reduction
   0x40232c:   cmp    ecx,ebp                             ; Compare to p
   0x40232e:   jb     0x402332                            ; If < p, continue
   0x402330:   sub    ecx,ebp                             ; ECX = ECX - p
   0x402332:   mov    DWORD PTR [ebx+0x8],ecx             ; Write component R2 of modular product
   0x402335:   pop    edx                                 ; Restore EDX
   0x402336:   pop    ecx                                 ; Restore ECX
   0x402337:   pop    eax                                 ; Restore EAX
   0x402338:   ret                                        ; End of modular multiplication




   0x402339:   pusha                                      ; Routine for inversion/transformation of mod p constants
   0x40233a:   mov    eax,DWORD PTR [esi]                 ; Load A0
   0x40233c:   mul    DWORD PTR ds:0x4040f4               ; Multiply by curve constant K0
   0x402342:   div    ebp                                 ; Modulo p (EBP)
   0x402344:   mov    DWORD PTR [ebx],edx                 ; Store R0 = (A0 * K0) mod p
   0x402346:   mov    eax,DWORD PTR [esi+0x4]              ; Load A1
   0x402349:   mul    DWORD PTR ds:0x4040f0               ; Multiply by curve constant K1
   0x40234f:   div    ebp                                 ; Modulo p
   0x402351:   mov    DWORD PTR [ebx+0x4],edx             ; Store R1 = (A1 * K1) mod p
   0x402354:   mov    eax,DWORD PTR [esi+0x8]              ; Load A2
   0x402357:   mov    DWORD PTR [ebx+0x8],eax             ; R2 = A2
   0x40235a:   mov    edi,ebx                             ; EDI points to the intermediate result
   0x40235c:   mov    ebx,0x404370                        ; Target buffer
   0x402361:   call   0x402292                            ; Full modular multiplication
   0x402366:   xchg   edi,ebx                             ; Swap buffer pointers
   0x402368:   mov    eax,DWORD PTR [edi]                 ; Load dword 0
   0x40236a:   mul    DWORD PTR ds:0x4040f4               ; Multiply by K0
   0x402370:   div    ebp                                 ; Modulo p
   0x402372:   mov    DWORD PTR [edi],edx                 ; Update dword 0
   0x402374:   mov    eax,DWORD PTR [edi+0x4]              ; Load dword 1
   0x402377:   mul    DWORD PTR ds:0x4040f0               ; Multiply by K1
   0x40237d:   div    ebp                                 ; Modulo p
   0x40237f:   mov    DWORD PTR [edi+0x4],edx             ; Update dword 1
   0x402382:   mov    eax,DWORD PTR [edi+0x4]              ; Load dword 1
   0x402385:   mul    DWORD PTR [esi]                     ; Multiply by A0
   0x402387:   div    ebp                                 ; Modulo p
   0x402389:   mov    ecx,edx                             ; ECX = Remainder
   0x40238b:   mov    eax,DWORD PTR [esi+0x4]              ; Load A1
   0x40238e:   mul    DWORD PTR [edi]                     ; Multiply by B0
   0x402390:   div    ebp                                 ; Modulo p
   0x402392:   add    ecx,edx                             ; Accumulate
   0x402394:   jb     0x40239a                            ; Overflow -> reduction
   0x402396:   cmp    ecx,ebp                             ; Compare to p
   0x402398:   jb     0x40239c                            ; If < p, continue
   0x40239a:   sub    ecx,ebp                             ; ECX = ECX - p
   0x40239c:   add    ecx,ecx                             ; Doubling
   0x40239e:   jb     0x4023a4                            ; Overflow -> reduction
   0x4023a0:   cmp    ecx,ebp                             ; Compare to p
   0x4023a2:   jb     0x4023a6                            ; If < p, continue
   0x4023a4:   sub    ecx,ebp                             ; ECX = ECX - p
   0x4023a6:   mov    eax,DWORD PTR [esi+0x8]              ; Load A2
   0x4023a9:   mul    DWORD PTR [edi+0x8]                 ; Multiply by B2
   0x4023ac:   div    ebp                                 ; Modulo p
   0x4023ae:   add    ecx,edx                             ; Accumulate
   0x4023b0:   jb     0x4023b6                            ; Overflow -> reduction
   0x4023b2:   cmp    ecx,ebp                             ; Compare to p
   0x4023b4:   jb     0x4023b8                            ; If < p, continue
   0x4023b6:   sub    ecx,ebp                             ; ECX = ECX - p
   0x4023b8:   mov    eax,ecx                             ; EAX = scalar value to invert
   0x4023ba:   call   0x4023dd                            ; Compute modular inverse: EAX = A^(-1) mod p
   0x4023bf:   mov    ecx,eax                             ; ECX = computed modular inverse
   0x4023c1:   mul    DWORD PTR [edi]                     ; Multiply B0 by modular inverse
   0x4023c3:   div    ebp                                 ; Modulo p
   0x4023c5:   mov    DWORD PTR [ebx],edx                 ; Store inverted dword 0
   0x4023c7:   mov    eax,DWORD PTR [edi+0x4]              ; Load B1
   0x4023ca:   mul    ecx                                 ; Multiply by modular inverse
   0x4023cc:   div    ebp                                 ; Modulo p
   0x4023ce:   mov    DWORD PTR [ebx+0x4],edx             ; Store inverted dword 1
   0x4023d1:   mov    eax,DWORD PTR [edi+0x8]              ; Load B2
   0x4023d4:   mul    ecx                                 ; Multiply by modular inverse
   0x4023d6:   div    ebp                                 ; Modulo p
   0x4023d8:   mov    DWORD PTR [ebx+0x8],edx             ; Store inverted dword 2
   0x4023db:   popa                                       ; Restore registers
   0x4023dc:   ret                                        ; End





   0x4023dd:   push   ebx                                 ; Extended Euclidean Algorithm: Modular inversion EAX^(-1) mod ebp
   0x4023de:   push   esi                                 ; Save ESI
   0x4023df:   push   edi                                 ; Save EDI
   0x4023e0:   cmp    eax,0x1                             ; Test if value is 0 or 1
   0x4023e3:   jbe    0x402413                            ; If EAX <= 1, inverse is the value itself (0 or 1)
   0x4023e5:   mov    esi,0x1                             ; ESI = Bézout coefficient x1 = 1
   0x4023ea:   mov    ecx,eax                             ; ECX = current value (A)
   0x4023ec:   xor    ebx,ebx                             ; EBX = Bézout coefficient x2 = 0
   0x4023ee:   mov    edi,ebp                             ; EDI = Modulo p
   0x4023f0:   mov    eax,edi                             ; EAX = EDI
   0x4023f2:   xor    edx,edx                             ; EDX = 0 for 64-bit division EDX:EAX
   0x4023f4:   div    ecx                                 ; EAX = Quotient (EDI / ECX), EDX = Remainder (EDI % ECX)
   0x4023f6:   test   edx,edx                             ; Is remainder zero? (End of Euclidean loop)
   0x4023f8:   je     0x40240b                            ; If Remainder == 0, end loop
   0x4023fa:   imul   eax,esi                             ; EAX = Quotient * x1
   0x4023fd:   sub    ebx,eax                             ; EBX = x2 - (Quotient * x1)
   0x4023ff:   mov    eax,esi                             ; EAX = x1
   0x402401:   mov    edi,ecx                             ; EDI = former divisor ECX
   0x402403:   mov    esi,ebx                             ; ESI = new coefficient x1 (EBX)
   0x402405:   mov    ecx,edx                             ; ECX = new divisor (Remainder EDX)
   0x402407:   mov    ebx,eax                             ; EBX = former x1
   0x402409:   jmp    0x4023f0                            ; Next iteration of Euclidean division
   0x40240b:   test   esi,esi                             ; Test if Bézout coefficient is negative
   0x40240d:   jge    0x402411                            ; If >= 0, valid result
   0x40240f:   add    esi,ebp                             ; If < 0, bring back to finite field: ESI = ESI + p (EBP)
   0x402411:   mov    eax,esi                             ; EAX = final computed modular inverse
   0x402413:   pop    edi                                 ; Restore EDI
   0x402414:   pop    esi                                 ; Restore ESI
   0x402415:   pop    ebx                                 ; Restore EBX
   0x402416:   ret                                        ; End of modular inversion

Enter fullscreen mode Exit fullscreen mode

A. Summary of Key Steps of the Mechanism

The binary does not merely compute an MD5 hash: it uses MD5 as an input block to feed an Elliptic Curve Cryptography (ECC) layer.

MD5 Initialization and Hashing (block 0x401700 to 0x401e2c)

  • Loading canonical MD5 constants (0x67452301, etc.).
  • Splitting the message into 64-byte (0x40) chunks and executing the 4 rounds of non-linear compression ( F,G,H,IF, G, H, I ).
  • Managing padding (adding the 0x80 byte, zero-padding, and appending the total message length at the end).
  • The resulting MD5 digest (16 bytes / 128 bits) is stored.

Conversion and Validity Verification (block 0x401e30 to 0x4020d0)

  • The MD5 result is used to instantiate one or two points on an elliptic curve.
  • The code extracts the X,Y,ZX, Y, Z coordinates of these points and performs geometric tests (checking whether the points lie on the curve or correspond to the point at infinity).

Finite Field Arithmetic (underlying blocks 0x402087 to 0x402416)

  • This is the underlying mathematical engine: it handles operations on large integers modulo pp (with the ebp register acting as a pointer/modulus value).
  • Modular Addition / Subtraction (0x402230, 0x402267).
  • Coordinate Multiplication (0x402292).
  • Modular Inversion via the Extended Euclidean Algorithm (0x4023dd).

B. Assembly Code Commentary

a. Phase 1: MD5 Implementation (0x401700 - 0x401e2c)

0x401700 - 0x40173e: Context Setup

  • Saving registers (pusha), retrieving the buffer and its length. Initializing state registers A,B,C,DA, B, C, D with canonical Little-Endian MD5 constants (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476).

0x401751 - 0x401d82: Compression Rounds

  • Round 1 (0x401768): Computes F(B,C,D)=(BC)(¬BD)F(B,C,D) = (B \land C) \lor (\neg B \land D) using not, and, or, adds the input word and sine constant via lea, then applies a rol rotation (shifts of 7, 12, 17, 22).
  • Round 2 (0x401917): Computes G(B,C,D)=(BD)(C¬D)G(B,C,D) = (B \land D) \lor (C \land \neg D) with shifts of 5, 9, 14, 20.
  • Round 3 (0x401ac6): Computes H(B,C,D)=BCDH(B,C,D) = B \oplus C \oplus D with shifts of 4, 11, 16, 23.
  • Round 4 (0x401c15): Computes I(B,C,D)=C(B¬D)I(B,C,D) = C \oplus (B \lor \neg D) with shifts of 6, 10, 15, 21.

0x401d84 - 0x401da6: Accumulation
The updated values in A,B,C,DA, B, C, D are added to the previous state variables, the input pointer advances by 64 bytes (add esi, 0x40), and the loop repeats if necessary.

0x401dab - 0x401e0f: Padding (MD5 Padding)
Appending the terminator byte 0x80 (mov BYTE PTR [edi], 0x80), calculating alignment (sub ecx, 0x37), filling with zeroes via rep stos, and writing the 64-bit total length (mul edx by 8).

0x401e10 - 0x401e2c: Hash Extraction
The 128-bit result is copied to the destination buffer passed as a parameter (rep movs), and registers are restored.

b. Phase 2: Elliptic Curve Cryptography (0x401e30 - 0x4020d0)

0x401e30 - 0x401ea0: Point Coordinate Verification
Loads the coordinates of two ECC points (esi and edi) and compares them. It validates projective or affine coordinates ( X,Y,ZX, Y, Z ) by performing subtractions modulo pp (stored in ebp, loaded from 0x40409c).

0x401ea6 - 0x401f60: ECC Point Addition
A series of call instructions to mathematical subroutines executing point addition/doubling on the curve.

0x401f9d - 0x40207e: Scalar Multiplication / Normalization
Takes the computed ECC point and converts it from projective to affine coordinates.

c. Phase 3: Modular Arithmetic Engine (0x402087 - 0x402416)

0x402180 - 0x4021ca: 64-bit × 64-bit multiplication with carry handling (adc).

0x402230 - 0x402266: Modular addition A+B(modp)A + B \pmod p (if the result exceeds ebp, ebp is subtracted).

0x402267 - 0x402291: Modular subtraction AB(modp)A - B \pmod p (if the result is negative, ebp is added).

0x402292 - 0x402338: Modular multiplication A×B(modp)A \times B \pmod p (uses the div ebp instruction to reduce modulo at each step).

0x4023dd - 0x402416: Modular inversion A1(modp)A^{-1} \pmod p based on the Extended Euclidean Algorithm (looping div ecx, imul, and adjusting with add esi, ebp if negative).

C. Can this hash function be inverted?

It is mathematically and practically impossible to invert this function to recover the original input from the output result.

The function is one-way (non-injective and irreversible) due to two major reasons:

a. Presence of a cryptographic hash (MD5)

The first phase of the function (blocks 0x401700 through 0x401e2c) is an exact implementation of the MD5 hashing algorithm.

  • Information Destruction (Overwriting): The compression logical operations ( F,G,H,IF, G, H, I ) and bitwise rotations (rol) scramble data, causing the loss of intermediate state values.
  • Compression/Collisions: A hash function compresses input data of arbitrary size into a fixed 128-bit (16-byte) digest. Thus, an infinite number of possible inputs produce the exact same output (pigeonhole principle).
b. Use of Elliptic Curve Cryptography (ECC)

The second part of the code (blocks 0x401e30 through 0x402416) processes the MD5 digest through elliptic curve arithmetic (scalar multiplications, operations modulo pp ).

  • Elliptic Curve Discrete Logarithm Problem (ECDLP): Even setting MD5 aside, if this function executes scalar multiplication of the form P=k×GP = k \times G (where kk is derived from your input and PP is the resulting point on the curve), finding kk from PP is the fundamental hard problem underlying modern public-key cryptography. It is considered computationally intractable in any realistic timeframe.
c. How can the input be "recovered" then?

Since you cannot invert the equation mathematically, the only applicable methods are:

  1. Brute-force (or dictionary) attack: Generating a massive volume of potential input candidates, running the function on each, and checking for matching outputs.
  2. Precomputed attack tables (e.g., Rainbow Tables): Applicable only if the analyzed output relies strictly on the MD5 phase without external variable parameters.
  3. SMT Solvers / Symbolic Execution (e.g., Z3, angr): If the input space is extremely short (e.g., a 4 to 8 character key/serial), a logic solver may successfully solve the mathematical constraints; however, the path explosion caused by MD5 makes this very difficult.

In summary: You cannot directly compute the input via mathematical formula inversion. The only viable path is to guess the input and verify the match.


5. Epilogue

The analysis of the hash function indicates that the easiest path to cracking this CrackMe is to solve the modular exponentiation equation by factoring the 64-bit modulus embedded in the program data. This will be covered in our next article on the topic.

Top comments (0)