Solution By:
meRlin
Run Singularity and enter your Name, No. of Licensed Copies
and a fake Serial No. Let's say:
Name:
LCNS
No. Of
License Copies: 99999
Serial
No: 12345678
The program checks every digits with the one which it expect to be. If any of
the digits failed to pass the jump then it'll show bad guy message. Now, when
you replace the first four digits with the real one at first CALL, then you have
to enter second CALL to check the remaining digits. Let's suppose you changed 8
with the valid one. Then you have to again change the first four digits because
the first four digits are based on last two digits which are 7 and 8
respectively. Don't get confused why this. You'll understand it when you read
the tutorial.
First let's check what is the maximum no. of licensed
copies supported by the program. We know that minimum is 1 don't we? Fire-up
S-Ice and put BPX GetWindowtextA. Press F11 one time. Now, we are inside the
program's routine. Press F10 until you reach at following address.
* Reference To: Sing32.?RCDlg_GetUserCount@@YAHPAUHWND__@@HPAGH@Z
|
:10011C8B E810FEFFFF call 10011AA0-----------Checks
the no. of licensed copies you entered with the maximum supported by the
program.
:10011C90 83C410
add esp, 00000010
:10011C93 85C0
test eax, eax-------------Return eax=1 if good guy.
:10011C95 0F846E010000 je 10011E09-----------------If
not then Bad Guy Message.
Let's
get inside the Call 10011AA0 and see what it actually does. When you are at
10011C8B press F8 and keep on pressing F10 until you reach at:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10011ACF(C)
|
:10011AD5 3DFF7F0000 cmp eax, 00007FFF--------What's
this.. Do ?eax you'll see 99999 and do ? 7FFF you'll see the maximum no. of
licensed copies supported by the program. It's 32767
:10011ADA 770B
ja 10011AE7-------------------Jump is above to Bad
Guy Message.
Now, exit S-ice and change the no. of
licensed copies to 32767.
-------------------------------------------
OK!
Now, let's go to the real thing. Fire up SoftICE, BPX GetWindowTextLengthA (or GetWindowTextA).
Do F11 one time and you land at :10011A6B. We are inside SING32.dll. Do BC* to clear
the BPX. Trace with F10 beyond the ret (ret to: 10011C6C). Before going any
further we suggest you do a deadlisting of the Sing32.dll in Wdasm and save it as a text file then come back reading! (check out Import functions)
* Reference To: USER32.GetWindowTextLengthA, Ord:015Fh
|
:10011A65 FF15E4020210 Call dword ptr [100202E4]
:10011A6B 3B4514 cmp eax, dword ptr
[ebp+14]-----We Land here!
:10011A6E 7C1D jl 10011A8D-------------------------------------Jump if Name
is less than 20h. Name must be less than 20h
characters.
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10011A6E(C)
|
:10011A8D FF7514 push [ebp+14]
:10011A90 FF7510 push [ebp+10]
:10011A93 56 push esi
* Reference To: USER32.GetWindowTextA, Ord:015Eh
|
:10011A94 FF15E0020210 Call dword ptr [100202E0]
:10011A9A 6A01 push 00000001
:10011A9C 58 pop eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10011A8B(U)
|
:10011A9D 5E pop esi
:10011A9E 5D pop ebp
:10011A9F C3 ret---------------------------Return To :10011C6C
-----------------------------------------------
:10011C6C 83C410 add esp, 00000010
:10011C6F 85C0 test eax, eax
:10011C71 0F8492010000 je 10011E09
.........More
Codes Follows Here!...........
---------Keep
on pressing F10 until you reach here!---------
* Reference To: Sing32.?il2@ri2@@QAEHXZ
|
:10011CB5 E872100000 call 10012D2C-------------Registration check
:10011CBA 85C0 test eax, eax-------------If success eax=1
:10011CBC 0F8583000000 jne 10011D45---------------If not jump->Wrong number
-----------------------------------------------------------------------
This is the main routine, you will always get out of this one
(ret to :10011CBA) with eax containing either 0 or 1 depending upon registration fail or success!
Here, we want esi+64 to be 1 (and it is if we registered already!)
* Referenced by a CALL at Addresses:
|:10010F62 , :10011CB5 , :100127E7
|
Exported fn(): ?il2@ri2@@QAEHXZ - Ord:04D4h
:10012D2C 56 push esi
:10012D2D 6A00 push 00000000
:10012D2F 8BF1 mov esi, ecx
:10012D31 6A00 push 00000000
* Reference To: Sing32.?gt2@ri2@@QAEGPADI@Z
|
:10012D33 E854000000 call 10012D8C------------------Get date and time etc..
:10012D38 6685C0 test ax, ax
:10012D3B 7525 jne 10012D62
:10012D3D 8BCE mov ecx, esi
* Reference To: Sing32.?iv1@ri2@@QAEHXZ
|
:10012D3F E8ECFDFFFF call 10012B30-----------------Validation routine
of the first 4 digits)
:10012D44 85C0 test eax, eax
:10012D46 7416 je 10012D5E--------------------Jump away bad guy
:10012D48 8BCE mov ecx, esi
* Reference To: Sing32.?iv2@ri2@@QAEHXZ
|
:10012D4A E8FBFDFFFF call
10012B4A----------------Validation routine of the
remaining digits)
:10012D4F 85C0 test eax, eax
:10012D51 740B je 10012D5E-------------------Jump away bad
guy
:10012D53 8BCE mov ecx, esi
* Reference To: Sing32.?iu2@ri2@@QAEHXZ
|
:10012D55 E8AAFFFFFF call
10012D04---------------Check if it is “Old Regcode”
:10012D5A 85C0 test eax, eax
:10012D5C 7404 je 10012D62-------------------Jump if it’s not
The simplest way to crack this
program is to change this:
xor eax, eax to xor al, 01
in this way you got eax=1 and then you change the jmp 10012D65 to jmp 10012D62.
If you do! Make the 3 key’s in registry and type anything you want ;-) (With one exeption!!
you need to change it so it look like this:
HKEY_LOCAL_MACHINE\SOFTWARE\WinAbility\Singularity\Setup\1 <-!!!
Better to sniff the valid code!! So press F8 when you are
at the CALL 10012B30.
-------------------------------------------------------------------------
Follow the registration calculation to sniff real regcode for your name and number
of copies entered. There is a lot of pointer’s moving around with our number, try to follow them
* Referenced by a CALL at Addresses:
|:10011CF5 , :10012B70 , :10012D3F
|
Exported fn(): ?iv1@ri2@@QAEHXZ - Ord:04D6h
:10012B30 8B4170 mov eax, dword ptr [ecx+70]
:10012B33 83C142 add ecx, 00000042--------------------(Do d ecx and you'll see the number you typed)
:10012B36 FF7038 push [eax+38]
:10012B39 FF7034 push [eax+34]
:10012B3C 8A4028 mov al, byte ptr [eax+28]-----Important value(53h=S)
:10012B3F 50 push eax---------------------------------------Push 53h
:10012B40 51 push ecx---------------------------------------Push Regnumber
* Reference To: Sing32.?riivc2@@YAHPBDDHH@Z
|
:10012B41 E8A6F8FFFF call 100123EC-----------------------------First checking
:10012B46 83C410 add esp, 00000010
:10012B49 C3 ret
Here is the first checking done at :100123F5 the first typed is compared
with (53h=S), is it not the same then xor eax, eax =0 ,else go on and check
next digit at :10012413 call 100122EB
* Referenced by a CALL at Address:
|:10012B41
Exported fn(): ?riivc2@@YAHPBDDHH@Z - Ord:04EDh
:100123EC 55 push ebp
:100123ED 8BEC mov ebp, esp
:100123EF 83EC20 sub esp, 00000020
:100123F2 8B4508 mov eax, dword ptr [ebp+08]
:100123F5 8A08 mov cl, byte ptr
[eax] –-------Depence what you typed as
first digit. But in our case 1
:100123F7 3A4D0C cmp cl, byte ptr [ebp+0C]----It’s compared with ebp+0C
which is equal to 53h=S. Do ? *(ebp+0C).
:100123FA 7549 jne 10012445------------------------------Jump away if it’s not.
Exit Softice and change first digit to S and again follow till here.
:100123FC 8D4DE0 lea ecx, dword ptr [ebp-20]
:100123FF 6A20 push 00000020
:10012401 51 push ecx
:10012402 6A00 push 00000000
:10012404 6A00 push 00000000
:10012406 50 push eax
:10012407 E836FFFFFF call 10012342
:1001240C FF7510 push [ebp+10]
:1001240F 8D45E3 lea eax, dword ptr
[ebp-1D]--Regnumber
:10012412 50 push eax
:10012413 E8D3FEFFFF call 100122EB--------------------------------Calculation
:10012418 83C41C add esp, 0000001C
:1001241B 3845E1 cmp byte ptr [ebp-1F],
al--------2nd digit. Do ? *(ebp-1F), you'll see
5432 and do ? al you'll see the no. that should be put in the place of 2. Exit
S-Ice and change 2 with the value inside al and follow till here.
:1001241E 7525 jne
10012445---------------------------------Jump away if it’s not
:10012420 FF7514 push [ebp+14]
:10012423 8D45E3 lea eax, dword ptr
[ebp-1D]----Regnumber
:10012426 50 push eax
:10012427 E8BFFEFFFF call 100122EB--------------------------------Calculation
:1001242C 3845E2 cmp byte ptr [ebp-1E],
al--------3rd digit. Do ? *(ebp-1E), you'll see
6543 and do ? *al you'll see the no. that should be put in the place of 3. Exit
S-Ice and change 3 with the value inside al and follow till here.
:1001242F 59 pop ecx
:10012430 59 pop ecx
:10012431 7512 jne
10012445----------------------------------Jump away if it’s not
:10012433 807DE339 cmp byte ptr [ebp-1D], 39--------Is the 4th
digit = 9
:10012437 7410 je
10012449-----------------------------------Jump if
it is!
:10012439 807DE338 cmp byte ptr [ebp-1D], 38-------Is the
4th digit = 8
:1001243D 740A je
10012449-----------------------------------Jump if it is!
:1001243F 807DE337 cmp byte ptr [ebp-1D], 37-------Is the
4th digit = 7
:10012443 7404 je
10012449-----------------------------------Jump if it is!
The
four digit must be equal to either 9, 8, or 7. So change it to the no. you like.
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:100123FA(C), :1001241E(C), :10012431(C)
|
:10012445 33C0 xor eax,
eax--------------------------------This is not good!!
:10012447 C9 leave
:10012448 C3 ret (eax=0)
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:10012437(C), :1001243D(C), :10012443(C)
|
:10012449 6A01 push
00000001-------------------------------Yes this OK!
:1001244B 58 pop eax
:1001244C C9 leave
:1001244D C3 ret (eax=1)
-------------------------------------------------------------------------------
Ok the first is done!
Now the name, number of copies and some number of regcode is brought together and calculated again.
So let's go inside the second CALL 10012B4A. Press F8 when you are at 10012D4A.
Now, you should see following:
Exported fn(): ?iv2@ri2@@QAEHXZ - Ord:04D7h
:10012B4A 8B4170
mov eax, dword ptr [ecx+70]
:10012B4D 8D5142 lea edx, dword ptr [ecx+42]
:10012B50 FF7030 push [eax+30]
:10012B53 6A01 push 00000001
:10012B55 FF702C push [eax+2C]
:10012B58 6A00 push 00000000
:10012B5A 52
push edx
:10012B5B 668B5140 mov dx, word ptr [ecx+40]
:10012B5F 52
push edx
:10012B60 FF7024 push [eax+24]
:10012B63 51
push ecx
* Reference To: Sing32.?riivn2@@YAHPBD0G0HHHH@Z
|
:10012B64 E8E5F8FFFF call 1001244E----------------This
is place where the remaining digits are compared with the valid digits. So let's
go inside this CALL press F8 when you are at 10012B64.
:10012B69 83C420
add esp, 00000020
:10012B6C C3
ret
Now,
you'll be here!
* Referenced by a CALL at Addresses:
|:10012B64 , :10012BA0
|
Exported fn(): ?riivn2@@YAHPBD0G0HHHH@Z - Ord:04EEh
:1001244E 55 push ebp
:1001244F 8BEC mov ebp, esp
:10012451 83EC64 sub esp, 00000064
:10012454 56 push esi
:10012455 57 push edi
:10012456 8D45DC lea eax, dword ptr [ebp-24]
------------More
Codes Follows Here!-----------
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1001248A(C)
|
:1001248F 8A45E0 mov al, byte ptr [ebp-20]
:10012492 6A40 push 00000040
:10012494 8845FC mov byte ptr [ebp-04], al
:10012497 8A45E1 mov al, byte ptr
[ebp-1F] ----Here
:1001249A 8845FD mov byte ptr [ebp-03], al
:1001249D 8D459C lea eax, dword ptr [ebp-64]
:100124A0 50 push eax
:100124A1 8D45FC lea eax, dword ptr [ebp-04]
:100124A4 50 push eax
:100124A5 FF7510 push [ebp+10]
:100124A8 56 push esi
:100124A9 E894FEFFFF call 10012342
:100124AE FF751C push [ebp+1C]
:100124B1 8D459C lea eax, dword ptr [ebp-64]
:100124B4 50 push eax
:100124B5 E831FEFFFF call 100122EB-----------------Here
it puts some of the number to our name and then calculate them again.(registered copys+two of regcode digits)
:100124BA 8B4D18 mov ecx, dword ptr [ebp+18]
:100124BD 83C41C add esp, 0000001C
:100124C0 38440DE2 cmp byte ptr [ebp+ecx-1E],
al--Compare again. Do ?
*(ebp+ecx-1E) you'll see 87 and do ? al you'll see the valid digit. Exit S-ice
and replace 7 with the valid digit.
:100124C4 5F pop edi
:100124C5 5E pop esi
:100124C6 7404 je
100124CC--------------------Jump if nice guy for the last check or no jump for bad cracker!
:100124C8 33C0 xor eax, eax-------------------If we NOT passed all the checking we got 0
in al=no good ;-)
:100124CA C9 leave
:100124CB C3 ret (eax=0)
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100124C6(C)
|
:100124CC FF7524 push [ebp+24]
:100124CF 8D459C lea eax, dword ptr [ebp-64]
:100124D2 50 push eax
:100124D3 E813FEFFFF call 100122EB--------------Calculation
:100124D8 8B5520 mov edx, dword ptr [ebp+20]
:100124DB 59 pop ecx
:100124DC 59 pop ecx
:100124DD 33C9 xor ecx, ecx
:100124DF 384415E2 cmp byte ptr [ebp+edx-1E],
al---Compare again. Do ? *(ebp-edx-1E), you'll see 8 and
do ? al you'll see the valid digit. Exit S-ice and replace 8 with the valid
digit.
:100124E3 0F94C1 sete
cl-------------------------If we passed all the checking we got 1 in cl=Good ;-)
:100124E6 8BC1 mov eax, ecx
:100124E8 C9 leave
:100124E9 C3 ret-----------------------------(eax=1)
We have traced through the codes and passed all checking. Now, EAX=1 then ret to :10012D5A
. The value in esi+64=1 futher away and ret to :10011CBA
This is where we came from (from the beginning) test eax, eax and we will pass with a valid number for our Name, Number of licensed copies and Registration Code.
Singularity is now cracked ;-)
---------------------------------------------------------------------------
Let's
collect more information about the program.
Calculation routine:
When
you are at:
:10012413 E8D3FEFFFF
call 100122EB
Press
F8 to go inside the CALL.
* Referenced by a CALL at Addresses:
|:10012413 , :10012427 , :100124B5 , :100124D3
|
:100122EB 660FB6542408 movzx dx, byte ptr [esp+08]
:100122F1 56 push esi
:100122F2 8B742408 mov esi, dword ptr [esp+08]
:100122F6 8BCA mov ecx, edx
:100122F8 8A06 mov al, byte ptr [esi]
:100122FA 84C0 test al, al
:100122FC 7434 je 10012332
:100122FE 57 push edi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1001232F(C)
|
:100122FF 8BFA mov edi, edx
:10012301 0FAFF9 imul edi, ecx
:10012304 660FBEC0 movsx ax, al
:10012308 46 inc esi
:10012309 8D4C07E1 lea ecx, dword ptr [edi+eax-1F]-Compare
again
:1001230D 84C9 test cl, cl
:1001230F 750A jne 1001231B
:10012311 33C0 xor eax, eax
:10012313 8AC5 mov al, ch
:10012315 33C9 xor ecx, ecx
:10012317 8AE8 mov ch, al
:10012319 0BCA or ecx, edx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1001230F(C)
|
:1001231B 33C0 xor eax, eax
:1001231D 8AC5 mov al, ch
:1001231F 84C0 test al, al
:10012321 7508 jne 1001232B
:10012323 33C0 xor eax, eax
:10012325 8AE2 mov ah, dl
:10012327 8AC1 mov al, cl
:10012329 8BC8 mov ecx, eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10012321(C)
|
:1001232B 8A06 mov al, byte ptr [esi]
:1001232D 84C0 test al, al
:1001232F 75CE jne 100122FF
:10012331 5F pop edi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100122FC(C)
|
:10012332 0FB7C1 movzx eax, cx
:10012335 6A0A push 0000000A
:10012337 99 cdq
:10012338 59 pop ecx
:10012339 5E pop esi
:1001233A F7F9 idiv ecx
:1001233C 8BC2 mov eax, edx
:1001233E 83C030 add eax,
00000030------------eax now contains the number which is Valid! to go on
(loop along with all the numbers through this place)
:10012341 C3 ret
If you want to see the Valid number for your name, check out the value of eax!
Singularity
is now fully cracked!