The.Winlicense.Tutorials.v1.2.1_SND.doc
Short Description
Download The.Winlicense.Tutorials.v1.2.1_SND.doc...
Description
The Winlicense tutorials v1.2.1 by quosego/snd 17-04-2009 Teddy suggested I put all my small tuts in one big paper, so this document holds all the tutorials I’ve made about Winlicense/Themida. It’ll be updated when needed, so make sure you got the latest version. Some of the topics discussed in this paper may get outdated quickly other things may only get slightly changed, if you get stuck it’s always best to just tinker along, reversing is only the result of a few idiots that tinkered along.
quosego
Contents The Winlicense tutorials v1.2.1.............................................................................. 1 Patching the Winlicense 2.0.5.0 - 2.0.7.0 Checksum..............................................3 Intro;................................................................................................................ 3 The checking;................................................................................................... 3 Analysis;........................................................................................................... 3 Patching the checksum 1.x until 2.0.5.0;.........................................................4 Patching the checksum 2.0.5.0 until 2.0.6.5;...................................................4 Patching the checksum 2.0.7.0........................................................................5 Finding the Winlicense Is_Registered dwords and patching them in Winlicense 2.0.6.5-2.0.7.0 (and lower)..................................................................................... 6 Intro;................................................................................................................ 6 Finding the dwords in 2.0.6.5;..........................................................................6 Finding the dwords in 2.0.7.0;..........................................................................7 Patching the dwords;........................................................................................ 8 Final notes;....................................................................................................... 9 The REGISTERED macro unraveled in Winlicense 2.0.6.5.....................................10 Intro;.............................................................................................................. 10 Analysis of the Cryptoblock function;.............................................................10 Analysis of the origin of the decryption dwords;............................................11 Analysis of the origin of the second decryption dword;..................................12 Analysis of the origin of the first decryption dword;.......................................12 Conclusion;.................................................................................................... 13
Using the is_registered dwords to bypass HWID and banning locks.....................14 Intro;.............................................................................................................. 14 Setting the is_registered dwords correct at the right time.............................14 The Stack Antidump in Winlicense and Themida 2.0.6.5......................................15 Intro;.............................................................................................................. 15 The location of the stackantidump;................................................................15 The method of checking antidump by the VM;...............................................15 Conclusion;.................................................................................................... 16 The LoadLibraryA antidump in WL an TM 2.0.7.0.................................................17 Intro;.............................................................................................................. 17 Finding the antidump location;.......................................................................17 Fixing the antidump;...................................................................................... 17 Final Notes;........................................................................................................... 18
Patching the Winlicense 2.0.5.0 - 2.0.7.0 Checksum. Intro; In this tut I'll try to explain how Winlicense checks if the app has been tampered with and how to patch it. The checking; Winlicense his anti patching procedure only holds an simple checksum check, it uses imagehlp.CheckSumMappedFile to compute this checksum and then compares it to the one stored by Winlicense and if it isn't the same it fails. To be exactly it does the following, -Alloc a memory buffer to store itself from disk. -Store the PE in this memory buffer. -Use GetProcaddress to obtain CheckSumMappedFile. -Use CheckSumMappedFile to compute a checksum. -Use some logical instructions to modify the checksum. -Compare the checksum to the one stored at the end of the file. -If it passes proceed, if it fails give an error. Analysis; If you'd breakpoint GetProcaddress and wait for quite some while sooner or later WL will obtain the CheckSumMappedFile location. If you'd then bp this api and return to WL code you'll end up somewhere similar to here; (If the app is using cisc VM, risc VM has a different VM entry.) 0112A5AF 0112A5B4
68 2C31AA09 ^ E9 3B7BF9FF
PUSH 9AA312C JMP 010C20F4
This'll of course leads you to nowhere since it's VM and studying it obfuud is greatly annoying. However if you look at the stack and scroll up four dwords you'll see the following; (these are simply the arguments pushed into CheckSumMappedFile) (http://msdn.microsoft.com/en-us/library/ms679281(VS.85).aspx) 0007FF6C 0007FF70 0007FF74 0007FF78
012A0000 000B41FC 0112A4D0 cisc_+_f.0112A4D0 0112A4D4 cisc_+_f.0112A4D4
and their meaning; PIMAGE_NT_HEADERS CheckSumMappedFile( __in PVOID BaseAddress, __in DWORD FileLength, __out PDWORD HeaderSum, __out PDWORD CheckSum ); The checksum is the most important (located at 0112A4D4). If you'd check out that dword you'll find the checksum. You can, if you've patched WL, feed it here
the correct checksum. But that would include hooking the WL decrypting routines or GetProcAddress or similar. There are easier methods. WL does not directly compare the CheckSumMappedFile generated checksum with a checksum it has stored, instead it does some computations before comparing the checksum. In my case it did the following computations, extracted from the Cisc Virtual Machine. ROL {checksum}, {last byte checksum} ;ROL 000B6D92,92 XOR B648002D,2AC8914C ADD 9C809161,87C05B78 XOR 2440ECD9,6D10B8E2
= B648002D = 9C809161 = 2440ECD9 = 4950543B
In this case 4950543B is considered the final calculated checksum. If you now set a memory breakpoint on access on the BaseAddress of the mapped PE (see the CheckSumMappedFile structure) in the memory map. You'll see the VM accessing the very last dword in the mapped file. This will if the executable is unmodified be the same as the calculated checksum. WL will next do a compare and fail or proceed. Patching the checksum 1.x until 2.0.5.0; So if you've modified your WL protected app you must update the checksum located in a dword at the end of the file, however as I stated all calculations of this checksum are done within the VM and it would be tedious to extract them every time. However WL stores the calculated checksum in the VM registers before comparing it with the stored one. So to find it easily you can do the following; - When you've returned from CheckSumMappedFile API memory bp the BaseAddress on access in the memory map. Press shift-f9. (It now has obtained the last dword of the mapped PE.) - Follow edi in dump and look for the first dword that appears two times, this is the calculated checksum. In cisc VM's it should be [edi+4] and [edi+8], in risc VM's it should be further down with some empty dwords between it. - Copy the calculated checksum to the end of the file (search for the old one or just scroll down). It'll now run again with its new checksum. Patching the checksum 2.0.5.0 until 2.0.6.5; There's not much they've updated, except it gets the CheckSumMappedFile API through the internal kernel32.dll GetProcAddress of Winlicense. So here's another method, though you can also bp the internal Getprocaddress and proceed with the above tutorial the following might be easier. - HW bp on access the last dword of the file that needs checksum updating and run. (This is the stored checksum, as you know) - Wait until it writes it using a rep to a memory buffer. - Then HW bp the checksum at the memory buffer. (eg. the last dword in the memory buffer.) Just follow EDI in dump and hw bp that dword. Run and wait until it gets accessed by the VM.
- Follow edi in dump and look for the first dword that appears two times, this is the calculated checksum. In cisc VM's it should be easy to spot, in risc VM's it should be further down with some empty dwords between it. - Copy the calculated checksum to the end of the file (search for the old one or just scroll down). It'll now run again with its new checksum. Patching the checksum 2.0.7.0 They’ve did some updates, not many interesting ones.. Generic idea is still the same, however one updates makes sure the previous tuts are useless; -Load the stored checksum prior to the calculations, this means when you hw bp it the new checksum won’t be in [EDI] anymore. They’ve probably made some other updates but since I didn’t notice them they are of no concern. But as usual they made a mistake so that once again an easy fix without VM digging is possible. To update the checksum in 2.0.7.0 follow the following tut. - bp FreeLibray, run and wait until it breaks, eax and ecx hold the old and calculated checksum. - Copy the calculated checksum to the end of the file (search for the old one or just scroll down). It'll now run again with its new checksum. Hmm kinda short tutorial.. Was hoping for more, but it seems oreans is not in the mood. This also works for the previous versions.
Finding the Winlicense Is_Registered dwords and patching them in Winlicense 2.0.6.5-2.0.7.0 (and lower). Intro; Most Winlicense protected apps simply rely on Winlicense to check for registration. They always do this using the WL API's and occasionally with some custom macro's. You can easily modify the API to return eax=1 and be done with it, however this usually does not fix the macro's/other custom checks or Trial checks. You can patch these as well and this is what I usually did. However it seems Winlicense only has two dwords it checks to see if it's registered, making sure that these hold the correct dwords registers the entire app with only a two dword patch. Update Notes for 2.0.6.5; Oreans has updated the dwords, and to be honest not as lame as the other updates. This time I'll have to guide you through the Virtual Machine to obtain the correct is_registered dwords. Since they're now no longer fixed and available in normal code. But don't worry, it'll be painless. :) Update Notes for 2.0.7.0; Oreans finally has hidden the is_registered dword correctly. They can no longer be found using the search strings used in the 2.0.6.5 version. All accesses to them are decrypted and encrypted when executed or VMed. The registered macro now uses a different dword to check if it’s registered. And finally the name api does not crash anymore when you’ve got the is_registered dwords fixed. Finding the dwords in 2.0.6.5; Not much updates here since the older versions, run the app and search for the following strings in the WL section. 1) B8 01 00 00 00 89 85 ?? ?? ?? ?? C7 85 Finds the following code; MOV EAX,1 // Not important MOV DWORD PTR SS:[EBP+xxxxxxxx],EAX // Not important MOV DWORD PTR SS:[EBP+xxxxxxxx], {Variable_1) // EBP+xxxxxxxx holds the dword (The EBP+xxxxxxxx in the third line of the found code is the location of the first is_registered dword) {Variable_1} is a random value, which WL checks for to see if it's not registered, however the correct value is not 2 here, but also random. If {Variable_1} equals the stored value then WL accepts the program as unregistered. 2) 00 00 00 00 00 00 00 00 81 BD Finds the following code;
CMP DWORD PTR SS:[EBP+xxxxxxxx],{Variable_2) (EBP+xxxxxxxx is the location of the second is_registered dword) {Variable_2) is in this case, the value the second is_registered dword needs to be. If the stored second is_registered dword equals {Variable_2) then WL accepts the program as registered. (If of course the first dword is also valid.) Put a hardware breakpoint on execute on the found addresses and restart the app. Next when you stop on these instructions you can read the memory locations which they compare to or write to. These are the locations were WL stores the is_registered dwords. Finding the dwords in 2.0.7.0; New search strings new chances. Start your app let it run and search for the following strings in the WL sections; 1) 50 53 B8 89 04 00 00 When found scroll up until you find something similar to this; Also it is possible that there’s also a “sub ecx,5 rep movs” instruction before this loop, search for it as mentioned in 2).
The above is a encryption/wiping loop, it overwrites everything above itself. As you probably can see above this is only bogus junk code that has already been wiped by the above loop. So HWBP on execute this loop and restart to see the function prior to being wiped. However make sure there’s not another loop slightly above this loop. If you’ve restarted and scrolled up to above the loop you’ll see the function that’s about to get wiped. Now in this function search for the following; CMP DWORD PTR SS:[EBP+xxxxxxxx], {Variable_1) holds the dword
// EBP+xxxxxxxx
Here the EBP+xxxxxxxx in this line of the found code is the location of the first is_registered dword. {Variable_1} is a random value, which WL checks for to see if it's not registered, however the correct value is not 2 here, but also random. If {Variable_1} equals the stored value then WL accepts the program as unregistered. 2) 50 53 8B C0 B8 9F 04 00 00 When found scroll up until you find the following (~10 lines); SUB ECX,5 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
However often olly doesn’t analyse the above code correctly so you can also search for the following byte string; 83 ?? 05 F3 A4. When found, HWBP it on execute and restart. Now scroll up and you’ll see another encryption/wiping loop that’s about to get wiped by the rep movs mentioned above. Now HWBP on execute this loop (wipe the previous HWBP) and restart. Now when you again scroll up you’ll once again see a function that’s about to get wiped. In this function search for the following; CMP DWORD PTR SS:[EBP+xxxxxxxx],{Variable_2) Here EBP+xxxxxxxx is the location of the second is_registered dword. {Variable_2) is in this case, the value the second is_registered dword needs to be. If the stored second is_registered dword equals {Variable_2) then WL accepts the program as registered. (If of course the first dword is also valid.) So now you’ve found the locations of the is_registered dwords in version 2.0.7.0 and the value that the second is_registered dword must be when registered. Patching the dwords; In previous versions the correct values of the is_registered dwords were fixed (2 & 500), however now they're randomly generated and using the information discussed in the previous paragraph you only know the correct value of the second dword. As for the first dword you only know the correct dword to make it unregistered. Which pretty much helps you nothing at all. I will now explain how you can trace the Oreans virtual machines to get the correct first is_registered dword. As you might know there are two possible Virtual Machines, Risc and Cisc. Since they differ in complexity and execution methods, I've made two tuts to find the first is_registered dword. Use the correct one for the correct VM. A simple rule is if the VM is located inside the WL section it's cisc, else it's risc. For version 2.0.6.5; Winlicense accesses and compares the correct first is_registered dword with the stored one the second time it accesses it in the VM. So first HW bp on access the location of the first dword. Then restart and press shift-f9 until you hit the code were it writes the {Variable_1). (See 1) in Finding the dwords.) Next press f9 and you'll be at the first access in the VM, next press f9 and you're at the second access. Next it'll compare the stored first is_registered dword with the correct one. Now you'll have to choose between the cisc or risc tut. For version 2.0.7.0; Winlicense accesses and compares the correct first is_registered dword with the stored one the third time it accesses it in the VM. So first HW bp on access the location of the first dword. Then restart and press shift-f9, first time you’ll break at a rep that writes zeroes and the second time you end up in the VM. Now press shift_f9 another two times and you’re near the compare to the correct value. Comparing in cisc Virtual machine; - Press F7 to arrive at the main lods handler, you can see {Variable_1) in the stack. - Put a breakpoint here and f9 until you see {Variable_1) in ecx
- eax now holds the correct is_registered dword. Store this at the first is_registered dword location and your app will be registered. (If you also fix the second of course.) You'll now prolly think, well that's nice but since I'm in this screwy virtual machine you better tell me why this actually works. Simple see the unobfuscated handler below which compares values in the cisc VM; POP EAX POP ECX CMP ECX,EAX PUSHFD JMP {Main_Handler)
// All handlers return to the main handler.
Since your {Variable_1) was pushed first it will be in ecx, and eax must hold whatever it is compared to. Junk VM code never writes stack values to eax or ecx so {Variable_1) can never get to ecx unless it's intended. (The above handler is unobfuscated, it can take extremely long if you try to trace and find this handler yourself.) Comparing in risc Virtual machine; - Trace until {Variable_1) which is retrieved from its store location is located at second dword of the stack, should be a pretty short trace 20 instructions max. 00391FF8 {Variable_1) 00391FFC
7EAC5730
View more...
Comments