首页
社区
课程
招聘
[求助]kioresk ExeCryptor lic analysis tut
发表于: 2009-5-20 01:16 2781

[求助]kioresk ExeCryptor lic analysis tut

2009-5-20 01:16
2781
I have kept this mail for a long time now as a private tut that kioresk have send me and i kept it private because i thoght that he will rls a tut .. but i guess that he is realy busy and don't have the time for this so i have now publish it to the public ..
this is the lic analysis for TransMac v8.1 (old rls...)
Enjoy!


I'll write complete tutorial later
(probably in the end of june), but since you are interested in it -
here are details about TransMac.


And let's go from the beginning - TransMac uses EC registration, so it
was compiled with EC modules and uses EC's API to validate
registration.

When you include EC's modules to your source code and compile it - it
would have EC's functions (not real functions, just stubs that later
will be replaced) somewhere in code section and references to them in
export directory.

Later, when you protect application, EC will place a redirect (that
points to virtualized code of function) in the beginning of each
function and remove references to them from export directory.

So, in case of TransMac EC function are located starting from address
406490. Here are list of them (addresses, sizes, names):

00406490 00000045 EXECryptor_GetDate
004064E0 00000011 EXECryptor_GetHardwareID
00406500 00000011 EXECryptor_IsAppProtected
00406520 00000014 EXECryptor_GetEXECryptorVersion
00406540 00000045 EXECryptor_GetReleaseDate
00406590 00000034 EXECryptor_EncryptStr
004065D0 00000034 EXECryptor_DecryptStr
00406610 00000021 EXECryptor_EncryptStrW
00406640 00000021 EXECryptor_DecryptStrW
00406670 00000015 EXECryptor_GetTrialDaysLeft
00406690 00000015 EXECryptor_GetTrialRunsLeft
004066B0 00000069 EXECryptor_SecureWrite
00406720 00000086 EXECryptor_SecureRead
004067B0 0000006B EXECryptor_SecureWriteW
00406820 00000088 EXECryptor_SecureReadW
004068B0 00000024 EXECryptor_MessageBox
004068E0 0000001C EXECryptor_GetProcAddr
00406900 0000000F EXECryptor_AntiDebug
00406910 0000000F EXECryptor_ProtectImport
00406920 00000016 EXECryptor_VerifySerialNumber
00406940 00000016 EXECryptor_VerifySerialNumberW
00406960 00000016 EXECryptor_DecodeSerialNumber
00406980 00000016 EXECryptor_DecodeSerialNumberW
004069A0 00000014 EXECryptor_IsRegistered
004069C0 0000000E EXECryptor_RegConst_0
004069D0 00000011 EXECryptor_RegConst_1
004069F0 00000011 EXECryptor_RegConst_2
00406A10 00000011 EXECryptor_RegConst_3
00406A30 00000011 EXECryptor_RegConst_4
00406A50 00000011 EXECryptor_RegConst_5
00406A70 00000011 EXECryptor_RegConst_6
00406A90 00000011 EXECryptor_RegConst_7

Ok, let's go on. Each of them have redirect in the beginning (jmp
poly). Redirects are used to hide calls to EC API's and looks like:

push ebp
push all regs
do calculations
pop all regs
pop ebp
jmp real function start

So to find start of each function, you need to move eip to start of
redirect, wait till it will push ebp (since code is virtualized and
obfuscated it can be made in many different ways), then place
breakpoint on read at [esp] and run (short script will do it).

After breaking at pop ebp (which can be obfuscated/virtualized too),
just follow 2
jumps (or push addr|ret, etc.) and you will be at the beginning of function.

Since application uses EC registration, it would call
EC_VerifySerialNumber to validate name/serial and can call
EC_IsRegistered/EC_DecodeSerialNumber in additional checks and for
getting parameters from key (allowed functions, type of license,
etc..).

Of course, instead of EC_VerifySerialNumber can be called
EC_VerifySerialNumberW (supports unicode), but unicode version just
prepares strings and then call EC_VerifySerialNumber too (all other
EC_...W functions do same).

So, if you check redirects for those funcions, you'll find that they
are points to:
00504727 EC_VerifySerialNumber
004FF502 EC_DecodeSerialNumber
004C69B3 EC_IsRegistered

Now, the most important part. What does EC_VerifySerialNumber function do?

I'll skip some details and will describe it generally - it converts
provided name/serial, transforms it with public key (in TransMac it's
located at address 004A4450). Then transforms result value with 8
given constants that are randomly defined for each protected
application (related to pub/private key) and stores result of each
transformation.

So, when you provide valid name/serial it will do some transformation,
generate 8 dwords and decide whether name/serial are valid. The most
important thing here are generated dwords - because they are used in
crypt_reg/crypt_unreg parts of code.

Each dword have only 1 valid value and of course their values are not
checked directly - dwords are used in calculations. Depending on
result of calculations - will be executed one part of code or another.

It's not easy to find correct values for that dwords without valid
name/key, because calucations are related to 2 or 3 dwords in the same
time, but it's possible (since i hadn't valid name/serial for TransMac
before).

I'll write about weakness that allows to find correct dword values
later (maybe already in tutorial).

Concerning code, that was attached to last section (.razum) of TransMac:
00534000 is patched EC_VerifySerialNumber
00534066 is patched EC_IsRegistered
0053406C is patched EC_DecodeSerialNumber (used for getting type of license)

Details about them you can find in EC's help (Serials API).

EC_VerifySerialNumber
=================
mov eax, [esp+4]
cmp byte ptr [eax], 0 ; check if name is empty
jnz short loc_53400E
xor eax, eax ; if empty, than return vr_Invalid and exit
retn 10h

loc_53400E: ; if not, than set dwords and return vr_Ok

mov ds:dword_41AE84, 2CD69EAAh
mov ds:dword_41B0E8, 0FCE7AB3h
mov ds:dword_41B0F8, 21EBA6B6h
mov ds:dword_41B108, 12532D33h
mov ds:dword_41B308, 1572D387h
mov ds:dword_41B30C, 0F2B723Fh
mov ds:dword_41B328, 1EC02CAAh
mov ds:dword_41B334, 247914F5h
mov eax, 3
retn 10h

EC_IsRegistered
============
mov eax, 3 ; return vr_Ok
retn

EC_DecodeSerialNumber
===================
pop ebp ; because it's patched after push ebp (there
were no space for placing jump our_code in the beninning)
mov eax, [esp+4] ; check if name is empty
cmp byte ptr [eax], 0
jnz short loc_53407B
xor eax, eax ; if empty, than return vr_Invalid and exit
retn 10h

loc_53407B: ; check if address for SerialNumberInfo is
also provided
mov eax, [esp+0Ch]
or eax, eax
jz short loc_534096

mov dword ptr [eax], 5 ; if provided, then put 5 to LicType (for
site license)
mov dword ptr [eax+10h], 01010101h ; set all 6 params (enabled features)
mov word ptr [eax+14h], 0101h

loc_534096:
mov eax, 3 ; if not, return vr_Ok and exit
retn 10h

Other changes are that you will find are:

1) ret at EC_Antidebug (00401604), because it stores all antidebug checks/tricks
2) nop at EC_OEP1 (004F4904)
3) ret at EC_OEP2 (0051108F)

A little bit about EC_OEP - when EC steal OEP, it put calls to 2 it's
functions in the beginning of OEP and only after executing them will
jump to place where commands from original OEP are stored (of course
they will be obfuscated/virtualized). So, generally OEP in protected
application looks like:

OEP:
call EC_OEP1
call EC_OEP2
jmp stolen_oep

In that functions there are checks (call to EC_Antidebug) and other
not needed code, so that's why they are patched too. To patch them you
just need to trace until ebp will be pushed and place ret at that
address to skip that call.


PS.
Hope your mind won't blow after reading it. ;-)

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//