GetDlgItem, GetDlgItemTextA, GetWindowTextA.
We release the program for execution, we drive in any name, key, and click the 'Check' button.GetDlgItemTextA
. We remove bryaki, and exit the API - we are standing at the address 0x0040195BCheckCode
function, which returns 0 or 1 depending on the result of the check. And, respectively, below MessageBox pair on true and false option of check. It is worth noting that, despite the absurdity of such protection, it is found in almost half of the applications. And if the goal is simply to get a working application, not a key, then you can replace call with a sequencexor al, al inc al
CheckCode
.GetOnlyNumeric
called by me GetOnlyNumeric
, it is passed, as a parameter, a pointer to the entered code.'A'-'F'
or '0'-'9'
, then it skips the character. If the symbol satisfies the condition, then merges it with a new line. This is done so that you can enter the key in a "beautiful" form, with delimiters.CheckCode
function code. At the address 0x00401457
you can see the counting of the length of the normalized string, and it should be equal to 24. (I have a typo here on the screenshot) . Why 24? REP SCASB
searches the string for a character from AL
, while decreasing the ECX
. Initially, ECX is indicated by 0xFFFFFFFF as the maximum value. Usually after this, the NOT ECX
and DEC ECX
commands are executed in order to get the length of the string in a normal form. We will do the same-1Ah = FFFFFFE6h not FFFFFFE6hh = 19h 19h - 1 = 24dec
sscanf
functions translate the normalized string into three binary DWORDs in a row. And at the very bottom of the screenshot there is a small loop that counts the hash from the entered name, by successive XOR
ten DWORDs of the buffer. (Buffer 40 characters long) At this point, the initial preparations are finished and the checks begin.EDI=ECX
.ECX
— right before the comparison, the LEA ECX, [ECX*4+ECX]
command is executed.LEA
is a command for calculating an address, but in this case it executes the expression: ECX = ECX*4 + ECX
or more simply ECX*5
. Going up the code, ECX is now found at 0x0040154F LEA ECX, [EDX*2+EDX]
. As they could have guessed it again, simple multiplication. It turns out that the final ECX = EDX*3*5
. But what then is the EDX
? If you potreitsit code, we understand that it is equal to the XOR
operation between the older and the younger part of the last key block. In the future, the resulting number will be called SUM, and poksorennye two bytes of the last block - CRC. Let me explain why the block - after translating the entered string into a binary form, all operations on them are performed either with a DWORD or with WORD values. Therefore, the type of key can be as follows:1111-2222-3333-4444-5555-6666
SUB EAX, 798134
. The resulting value, then KEY1, is stored in a variable, and from it gets 4 half-bytes (4 bits), located in positions 2, 3, 6, 7 (numbering from 0) and are multiplied together. The resulting value and should be ECX
. The first thing that comes to mind is to calculate such values at which both crc and KEY1 would equal 0. It seems all is well, but it would be too simple, with this option all checks except the last one are passed. But more about that later.EDX
, before it becomes KEY1. From the comments it can be understood that at first it is considered from the younger part of the hash on behalf of block1 and block2, again using XOR
. Then two operations are performed.XOR EAX, 9F827364 SUB EAX, 798134
ADD EAX, 798134 XOR EAX, 9F827364
ADD ECX, 871623 XOR ECX, 4637A819
XOR ECX, 4637A819 SUB ECX, 871623
0x00401654
, there is a very small check CMP SI, BX
. It is not complicated, and again, by treys, you can see that the younger part of the hash is compared on behalf of the fifth block of the entered code. The remaining three checks are also small: 0x004016BF
. Here it is, and it is the most insidious - it compares crc, or more simply the poksorennye bytes of the last block, on which all previous checks depend. And which actually does not allow us to make KEY1 and KEY2 zero.SHL EDX, 1
command shifts 1 bit to the left, which is equivalent to multiplying a number by 2. Thus, we find that the number of the poxor number is a constant for any code and should be 0xB6 / 2 = 0x5B.0x6930622F
. The upper part is not involved in the algorithm.5d7337d5 d537735d
.(5d7337d5 + 798134) ^ 9F827364 = C26ECA6D block1 = C26E ^ 622F = A041 block2 = CA6D ^ 622F = A842 (d537735d ^ 4637A819) - 871623 = 9279C521 block3 = 9279 ^ 622F = F056 block4 = C521 ^ 622F = A70E
A041-A842-F056-A70E-622F-005B
Source: https://habr.com/ru/post/134817/
All Articles