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
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 address0x404048(mov bl, 0x3ffrom 63 down to 0) to map the characters. -
Padding Handling (
0x00401687and0x004016a4): It looks for the=character (0x3D) and incrementsdhto 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 rotationsrol 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 ( , 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 (
0x0040153eand0x00401567): The 64-bit integers are compared (viasub/sbb/jae) against a modulus or maximum value stored at0x40403c. -
Modular Operations (
0x00401591and0x0040159d: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:
- Phase 1 (Format): Conversion of the 24-character Serial (Base64) into a 16-byte (128-bit) binary buffer.
- Phase 2 (Mathematics): Processing the 128 bits as two 64-bit integers subjected to modular exponentiation equations.
-
Phase 3 (Name/Key Binding): A fingerprint derived from the
Nameis injected via a XOR mask to verify final equality (or eax, edxjne 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:
- Extraction: The Serial (24 Base64 chars) is decoded into a 128-bit block divided into two 64-bit integers: and .
- Modular Computation: The program executes a modular exponentiation:
-
Binding with the Name: The result
is combined via a XOR mask with a fingerprint of the
Name:
-
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 .
a. Why and how is this function inverted?
The verification process executes the following public operation:
To build a key generator (Keygen) for a given Name, the process involves inverting this equation:
-
Computing the Name Hash: You pass the
Namethrough the hashing function0x00401700to obtain the fingerprint . - Reconstructing the Target: By analyzing the XOR operations and modular adjustments in Phase 4, you deduce the target value that the calculation must yield.
- Calculating the Private Key :
- You retrieve the modulus
(at address
0x40403c) and the public exponent (at address0x404020). - Since
is a 64-bit integer (i.e., 8 bytes, visible with the 32-bit
sub/sbbinstructions), its factorization into two prime numbers and is instantaneous on a modern computer (using a tool like PARI/GP, SageMath, or Factordb). - Once
and
are known, you calculate Euler's totient function
, and then the private exponent such that:
- Calculating : You recover the original value by applying the private key:
-
Final Encoding: You assemble the 16-byte block
and pass it through the Base64 encoder using the custom alphabet located at address
0x404048.
b. The Invertibility Condition
- If the modulus 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 had been 2048-bit: The function would be mathematically invertible in theory, but practically unbreakable without knowing the private key , 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
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 ( ).
- Managing padding (adding the
0x80byte, 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 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
(with the
ebpregister 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 with canonical Little-Endian MD5 constants (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476).
0x401751 - 0x401d82: Compression Rounds
- Round 1 (0x401768): Computes
using
not,and,or, adds the input word and sine constant vialea, then applies arolrotation (shifts of 7, 12, 17, 22). - Round 2 (0x401917): Computes with shifts of 5, 9, 14, 20.
- Round 3 (0x401ac6): Computes with shifts of 4, 11, 16, 23.
- Round 4 (0x401c15): Computes with shifts of 6, 10, 15, 21.
0x401d84 - 0x401da6: Accumulation
The updated values in
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 (
) by performing subtractions modulo
(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
(if the result exceeds ebp, ebp is subtracted).
0x402267 - 0x402291: Modular subtraction
(if the result is negative, ebp is added).
0x402292 - 0x402338: Modular multiplication
(uses the div ebp instruction to reduce modulo at each step).
0x4023dd - 0x402416: Modular inversion
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 (
) 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
).
- Elliptic Curve Discrete Logarithm Problem (ECDLP): Even setting MD5 aside, if this function executes scalar multiplication of the form (where is derived from your input and is the resulting point on the curve), finding from 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:
- Brute-force (or dictionary) attack: Generating a massive volume of potential input candidates, running the function on each, and checking for matching outputs.
- Precomputed attack tables (e.g., Rainbow Tables): Applicable only if the analyzed output relies strictly on the MD5 phase without external variable parameters.
- 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)