Professional Documents
Culture Documents
- thewinlicensetutorialsv121snddoc - 副本
- thewinlicensetutorialsv121snddoc - 副本
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.
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.)
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;
0007FF6C 012A0000
0007FF70 000B41FC
0007FF74 0112A4D0 cisc_+_f.0112A4D0
0007FF78 0112A4D4 cisc_+_f.0112A4D4
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.
In my case it did the following computations, extracted from the Cisc Virtual
Machine.
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.
- 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.
-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.
1)
B8 01 00 00 00 89 85 ?? ?? ?? ?? C7 85
(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
{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.
Start your app let it run and search for the following strings in the WL sections;
1)
50 53 B8 89 04 00 00
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;
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;
{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.
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.
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.)
- Hardware bp that stack address on access (here 391ff8), and run. When it
breaks the correct is_registered dword is now located in the dword above the old
one in the stack. Store this dword at the first is_registered dword location and
your app will be registered. (If you also fix the second of course.)
Once again you might ask yourself and why does this work?? And again once you
know the unobfuscated code all becomes clear;
Well that's all, after you've unpacked the app just set the first and second dwords
correctly and everything will once be registered. Or use an inline to fix these
dwords after the app has been unpacked in memory.
Final notes;
Once again Winlicense can crypt certain blocks of code using dwords written
when a keyfile is present, these will not be decrypted and can crash. Also the
Get_name API will crash! Since there's no name you can put a ret 0c in its place
which most apps will accept or patch it to return a name.
The REGISTERED macro unraveled in Winlicense 2.0.6.5
Intro;
In this part of my series about Winlicense I'll unravel the decryption of certain
code parts that use the REGISTERED_START REGISTERED_END macro. This tut
won't be as directly useful as the previous parts. Since you prolly still need a
correct keyfile to fix these blocks, and after you've unpacked an app with a key
it's unnecessary to do anything with these blocks. But still it'll give you a nice
idea what Winlicense does and how it uses the keyfiles.
Once again this'll include some VM tracing and analysis. Please note, I make use
of an unobfuscated Virtual Machine. Sadly enough the techniques developed by
me and others to unobfuscate VM's are not publicly available, except for the
recent release of the Code Unvirtualizer 0.1 by Deathway which has this
implemented. You can use this tool to do some analysis yourself if you wish to
expand on this tutorial. I however have not used this tool so I don't know its
effectiveness. I will however try to make it so that you can even follow this tut
with an obfuscated cisc VM.
E8??????00????00000000000000????2020
This'll lead you to a call to the REGISTERED macro, below I'll explain an example
of such a REGISTERED macro in parts.
PUSHAD
CALL 0064EC8F //call the line below
POP EBP //pop call return address into ebp
SUB EBP,9D41080 //substract to get correct ebp value
As often the case with Themida and Winlicense uses EBP to get memory
locations.
(eg MOV DWORD PTR SS:[EBP+9D41076],ESI now equals for instance, MOV
DWORD PTR SS:
[00551849],ESI)
MOV ESI,DWORD PTR SS:[ESP+20] //load the address from which the
macro was called
[2];
CMP DWORD PTR DS:[ESI],20204C57 //are we at the beginning/end
JNZ [1]
CMP DWORD PTR DS:[ESI+4],3 //are we at the last 20204c57 (end)
JE 0064ECB6
[1];
INC ESI
JMP [2]
SUB ESI,2
MOV DWORD PTR SS:[EBP+9D41076],ESI
Store the address that marks the end of the encrypted data.
Check for the is_registered dwords, also a nice place to see what they are
supposed to be. Though not always available.
[3];
CMP ESI,DWORD PTR SS:[EBP+9D41076]
JE [exit]
Load start address of the cryptoblock to decrypt, and compare to the end of the
block.
Decrypt the block using the EAX and EBX dwords a simple decryption routine.
---
First, something about the VM. It has the following simplified structure, a main
handler interprets bytes and jumps to the accompanying specific handler. This
handler executes its code and the main handler interprets the next byte.
So the main handler gets byte 31, decrypts it and sees that byte 31 means
executing handler number 4 which pushes ebx. It'll jump to the "push
ebx/number 4 handler" which will push ebx and go back to the main handler. Now
it'll get the next byte and so on.
---
Hw bp the VM register (follow EDI in dump and find the decryption value) that
contains the first decryption dword. Next time it'll be accessed it'll be for the
calculation of the second decryption dword, and it'll have pushed it onto the
stack. You can also find this by bping the main handler and see the dword
appearing in the stack. Unless you've deobfuscated your VM I don't suggest
tracing through specific handlers. There are ~30 handlers between the writing of
the first dword and the calculation of the second.
Next you can bp this dword in the stack to see where it gets accessed, (remove
the previous one) once again unless you've got no obfu don't trace since there's a
lot of junk code between normal instructions. (push pops, word loads, 4 adds.
etc.) You'll end up in a handler doing the following;
POP EAX
ADD DWORD PTR SS:[ESP],EAX
PUSHFD
JMP {Main_Handler)
[ESP] holds a fixed value loaded from VM_code and eax holds the first decryption
dword. It should be obvious that they get added to each other here.. Now check
out the value in the stack, indeed it's the second decryption dword.
So you now know the second decryption dword is derived from the first. However
that does not tell us anything about the origin of the first dword. This will be
discussed in the next chapter.
Analysis of the origin of the first decryption dword;
Restart the app and use an hw bp on access on the first decryption dword
location to once again break in the VM were it writes this dword. However right
now you're already too late, the decryption has both been calculated and written.
But as you might have noticed the main handler loads VM_code bytes from ESI
which makes it decide which handler it needs to call, this is the actual code being
executed right now in the VM. So why not scroll back a bit here and put a bp
earlier in the VM. So follow ESI in dump, marvel at the encrypted VM_code scroll
up about 13 lines. There's lots of junk in VM_code so you can scroll up quite some
bytes. (Please note that the amount of lines is guesswork, the amount of
junkcode is variable.)
Hw bp this byte on access and restart and f9 until you're in the VM. If you now
follow EDI in dump to see the VM_registers, you must check to see if the first
decryption dword is no longer in the VM registers. If it still is then you've not
scrolled up enough lines. The first VM_register ( simply [EDI] ) holds an
interesting value, a memory buffer. A few lines down in another VM_register
there's the first dword located at this memory buffer.
Right now I'll just tell you that the 2660000 is the memory buffer holding the
keyfile which went through a few decryptions. Hw bp this address and restart to
find out for yourself.
Now hw bp the VM_register containing the first dword of the keyfile memory
buffer. (In the above example the one with A3D9D3B7.) and press f9. When you
break it'll have pushed this value on the stack. Next you can bp this dword in the
stack to see where it gets accessed,(remove the previous one). You'll end up in a
handler doing the following;
POP EAX
XOR DWORD PTR SS:[ESP],EAX
PUSHFD
JMP {Main_Handler)
Check the stack and you'll see the first decryption dword.
We now know that the first decryption dword is derived from the first decrypted
dword of the keyfile. The first decryption dword is then used to calculate the
second decryption dword.
Conclusion;
To decrypt certain codeparts in registered Winlicense protected apps Winlicense
uses the first dword of the keyfile to calculate the decryption dwords. These
dwords then get used to decrypt the REGISTERED macro's encrypted code/data.
This tut will simply show hoe you can use the is_registered dwords to make
programs that use banned license and wrong HWID’s work once more. These
apps however require unpacking, loaders or inlines to keep working.
HWID;
This one is quite simple and won’t require much explanation. Normally you’ll get
two message boxes when you try to run a program with a license meant for a
different computer;
Simply modifying the is_registered dwords at the first message box to their
correct values will make the program run.
Banned License;
Here you’ve only got a message box saying that your license has been banned.
So we’ll need to dig somewhat further. Not too much though.
Put an hw bp on write on the second is_registered dword and run. First you’ll see
it zeroed and then changed to the correct value and then to a different value.
Now change it to the correct value again and the program runs.
Quite simple and whole lot easier than digging VM searching for zeroes and 1 and
other HWID tricks. Trial values etc. can also be fixed using these kinds of tricks.
The Stack Antidump in Winlicense and Themida 2.0.6.5
Intro;
Yes this is it; I will now explain the complete workings of the stack antidump.
Though this is just one antidump, there are many more, it is the one I know best.
The other antidumps will stay a mystery until someone decides to make a tut
about these.
The antidumps are checks by the Oreans Virtual Machine to see if it was dumped.
If it is it’ll check these and if not available the VM will produce an error. The
stackantidump in particular is a check for a qword in the stack. If it’s not
available, the check for it in the Virtual machine will not pass.
I will not tell you how to defeat it, only what makes it tick. You should be able to
defeat it yourself.
Now when you unpack an app the app will once again start at xxffc4 and all those
values Winlicense or Themida put before their oep will not be there, the stack
gets wiped when you restart a program. The VM makes use of this by checking
these addresses for their correct values. When unpacked these values are not
there so the VM knows it’s been dumped.
The above stores 2 dwords that the VM will later use to check stackantidump,
data_1 and data_2. Data_1 holds the variable that must be the same when
[xxffc0] and [xxffc0+4] are xorred. Data_2 holds the location xorred with
fixed_value_2, the VM will use data_2 to calculate where the stackantidump is
located.
Conclusion;
To check if the VM is dumped the VM checks certain values in the stack. It then
xors these values and checks if they are the same as a stored value. If they are
not the VM will take action to prevent execution.
The LoadLibraryA antidump in WL an TM 2.0.7.0
Intro;
In this tut I’ll show you how to defeat the newest antidump in Winlicense and
Themida 2.0.7.0, the first few apps have emerged using the new version and
have proven to be unable to run on most other computers when unpacked. This is
because Oreans has implemented a new antidump based on the location of the
kernel32 dll in memory. This differs in most OS’s and service packs.
Example;
When runned the packer shell get’s the LoadLibraryA location and get’s the
dword located at LoadLibraryA+16. It now stores the location of LoadLibraryA in
Themida data and also stores the LoadLibraryA+16 dword. You unpack the app
and dump this WL/TM data to disk.
Okay so now run it on some other computer with a wholly different LoadLibraryA
location (a different OS/SP is usually enough). The VM gets the location of what it
thinks to be LoadLibraryA from the WL/TM data en adds 16 to it, then it checks if
the bytes here are the same as the bytes originally stored by packer code. It’ll
now notice that they differ and knows you’re running it on a different computer.
Thank you all for reading this, hope you enjoyed it.
Greetings to all webscene teams, and the reversers visiting the RE boards and
thnx to a certain provider of executables.
-q