LaBBa
May 19th, 2009, 11:38
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!
edit: i hope that kioresk won't be mad that i have made his private conversation with me to a public matter but i relay on kioresk that he is a persone that support the share of information and he told me that he was going to publish this tut in june last year ..
and since the protection is already updated i think there is no damage to none by publishing old info..
this is the lic analysis for TransMac v8.1 (old rls...)
Enjoy!
edit: i hope that kioresk won't be mad that i have made his private conversation with me to a public matter but i relay on kioresk that he is a persone that support the share of information and he told me that he was going to publish this tut in june last year ..
and since the protection is already updated i think there is no damage to none by publishing old info..
Quote:
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. ;-) |