(With an add-on by Marigold, 16 Jan 1998)
||As it seems, we have entered the "new deal": we
are beginning to produce our own tools (was about time: the whole +HCU
1998 will be centered on some 'our own tools' projects :-)... yet you'll
find a lot more inside this VERY GOOD essay by Uncle Van: self-correcting,
real code hiding, how to adjust the PE header, Uncle Van's 'precracking',
bypassing the WriteProcessMemory and a lot of other goodies... (I love
Uncle Van's approach: "there will be really "man
against man", I see glorious days coming"... I agree totally! The
more the protectionists learn, the more fun it is to crack their 'advanced'
Work well: you'll have a couple of days work just to understand what Uncle Van is explaining you... and that's the nice part of our trade! To learn! Knowledge is knowledge's reward!
||( )Beginner ( )Intermediate
(x)Advanced ( )Expert
An understanding of common advanced cracking techniques is a pre-requisite. Don't even try to follow this if you are a beginner (in that case come back later).
||Encoded selfmodifying targets - the
Power Desk suite from Mijenix
OK, I know it sounds pretty earnest but it hits the point of this essay.
Written by Uncle Van
ImpressumWell, this is the greatest discussion nowadays, concerning the software protection - Is it possible under such "allmighty" OS like windo$e (but also all other protected mode systems) to write into one's own code in order to protect his product against (banal) patches and unexpirienced cracker?
It's first necessary to know about memory protection, that Intel's x86 line has two general modes - real and protected - and furthermore in protected mode it can operate in 4 security "rings" - ring 0 till ring 3.
Every ring corresponds to an appropriate privilege level - the higher the number the lower the privilege level. This means, that p.e. in ring 0 ALL opcodes are allowed and there is no restriction in the terms of memory access, it's just like in old "real" DOS, you can rampage everything you fancy ;=D.
But as you walk to the higher ring number more and more restrictions appears: several opcodes get disabled, you are not allowed to acces memory regions you not own, IN and OUT instructions are getting "controlled", and at least, you can't even write to your own code segments because it is write protected too. (Here I'm not so sure!)
You can "jump" from a ring with higher privilege to code in rings with lower privilege, but not vice versa.
In the windo$e world applications run of course in the ring 3 mode ;-(, while the main part of the OS itself AND the drivers (Vxd!) operate at ring 0. And as we already know from Reversers page, overwriting the own code is essential for a good protection. The most cool protections BTW were made in DOS real-mode times, some of them are not cracked yet!
The main problem is how could a program overwtite its own code on such OS? At this point I'll qoute +rcg from his First Attempt:http://fravia.org/pro_rcg.htm
"......... VxD. I know this is a big effort, but I'm sure we will be able to program them in a few months, so we will take again the control over the system (just like we did in Ms-Dos)."It must be really a big effort since we didn't hear something new about this ;-) You can read Reverser's essay about VxDs too in order to get a first impression about such a stuff.
I'll show you here how the guys from Mijenix solved this problem.
ASCII dump importer (our own)
A textEditor which allows block selecting
Of course, you may choose any other tools you like.
Theme:Power Desk eval v202, to obtain from: http://www.mijenix.com
These are indeed a couple of utilities inluding an OLE container designed
for the "power user" ;-) to maintain your desktop tasks etcetera. I'm concentrated
on a program named Pdexplo.exe, an advanced explorer. I don't use such
kind of stuff but some among you seem to like it (thanks Stefan for the
............... 0137:0044656C 8B3D54174500 MOV EDI,[KERNEL32!GetLocalTime];<==== ! 0137:00446572 C605C3A9440055 MOV BYTE PTR [0044A9C3],55 0137:00446579 C605C7A9440055 MOV BYTE PTR [0044A9C7],55 0137:00446580 C705C8A94400E8030000MOV DWORD PTR [0044A9C8],000003E8 0137:0044658A FFD7 CALL EDI ; <========= !!!!!!!!!!!!!! 0137:0044658C 66817C2418CC07 CMP WORD PTR [ESP+18],07CC 0137:00446593 744E JZ 004465E3 ;>===================>| 0137:00446595 66817C2418CD07 CMP WORD PTR [ESP+18],07CD | 0137:0044659C 7445 JZ 004465E3 ;>===================>| 0137:0044659E 66817C2418CE07 CMP WORD PTR [ESP+18],07CE | 0137:004465A5 743C JZ 004465E3 ;>===================>| 0137:004465A7 6A10 PUSH 10 | 0137:004465A9 FE0DC4A94400 DEC BYTE PTR [0044A9C4] | 0137:004465AF C605C6A9440009 MOV BYTE PTR [0044A9C6],09 | .................By slightly rejumping it we can start the target regardless of expired dates and periods, but the attempt to locate the checks with hexeditor or Wdasm fails. Disassembling the program we see at the above addresses:
................. :0044656C 00000000000000000000 BYTE 10 DUP(0) :00446576 00000000000000000000 BYTE 10 DUP(0) :00446580 00000000000000000000 BYTE 10 DUP(0) ..............Really tough, eh?
Which tricks they have used to hide the real code until program start? The right assumption is that this piece of code is somewhere in the data area and is evntl. decoded and "paste" in the right place at run time.
How they do it?
Looking at the imported functions we see some with very meaningfull names like:
............... KERNEL32.GetCurrentProcess KERNEL32.GetCurrentProcessId KERNEL32.OpenProcess KERNEL32.ReadProcessMemory KERNEL32.WriteProcessMemory ...............What you say? These could be the ones!
According to micro$oft manuals a process is a "fundamental" term in their(!) OS and
"..when You start a program from the disk it becames a process."Aha! And in fact you can do many things with a process - getting its handle, opening it, reading from its memory AND WRITING TO IT, if you have the necessary rights; but when you own a process you have all rights as well!
So we BPX ReadProcessMemory in SoftIce and load the target. And BINGO!
.................. 0137:00439FA0 81EC64010000 SUB ESP,00000164 0137:00439FA6 53 PUSH EBX 0137:00439FA7 56 PUSH ESI 0137:00439FA8 57 PUSH EDI 0137:00439FA9 55 PUSH EBP 0137:00439FAA 33FF XOR EDI,EDI 0137:00439FAC FF1578174500 CALL [KERNEL32!GetCurrentProcessId] 0137:00439FB2 50 PUSH EAX 0137:00439FB3 57 PUSH EDI 0137:00439FB4 6A38 PUSH 38 0137:00439FB6 FF1530174500 CALL [KERNEL32!OpenProcess] 0137:00439FBC 8BF0 MOV ESI,EAX 0137:00439FBE 57 PUSH EDI 0137:00439FBF 8D442440 LEA EAX,[ESP+40] 0137:00439FC3 6A40 PUSH 40 0137:00439FC5 8B8C2480010000 MOV ECX,[ESP+00000180] 0137:00439FCC 50 PUSH EAX 0137:00439FCD 51 PUSH ECX 0137:00439FCE 56 PUSH ESI 0137:00439FCF FF1574174500 CALL [KERNEL32!ReadProcessMemory] 0137:00439FD5 8BAC2478010000 MOV EBP,[ESP+00000178] 0137:00439FDC 57 PUSH EDI 0137:00439FDD 036C247C ADD EBP,[ESP+7C] 0137:00439FE1 68F8000000 PUSH 000000F8 0137:00439FE6 8D842484000000 LEA EAX,[ESP+00000084] 0137:00439FED 33DB XOR EBX,EBX 0137:00439FEF 50 PUSH EAX 0137:00439FF0 55 PUSH EBP 0137:00439FF1 56 PUSH ESI 0137:00439FF2 FF1574174500 CALL [KERNEL32!ReadProcessMemory] 0137:00439FF8 6639BC2482000000 CMP [ESP+00000082],DI 0137:0043A000 7641 JBE 0043A043 0137:0043A002 8D442414 LEA EAX,[ESP+14] 0137:0043A006 6A00 PUSH 00 0137:0043A008 6A28 PUSH 28 0137:0043A00A 50 PUSH EAX 0137:0043A00B 8D042F LEA EAX,[EBP+EDI] 0137:0043A00E 05F8000000 ADD EAX,000000F8 0137:0043A013 50 PUSH EAX 0137:0043A014 56 PUSH ESI 0137:0043A015 FF1574174500 CALL [KERNEL32!ReadProcessMemory] : : : 0137:0043A0D4 50 PUSH EAX ; <== PCount = 0 0137:0043A0D5 83E103 AND ECX,03 0137:0043A0D8 F3AA REPZ STOSB 0137:0043A0DA 8B542420 MOV EDX,[ESP+20] 0137:0043A0DE A164E64400 MOV EAX,[0044E664] 0137:0043A0E3 8B4C2414 MOV ECX,[ESP+14] 0137:0043A0E7 52 PUSH EDX ; <== Count = 1C4B bytes to read 0137:0043A0E8 50 PUSH EAX ; <= buffer in memory to save it 0137:0043A0E9 51 PUSH ECX ; <= address to read from = 445000h 0137:0043A0EA 56 PUSH ESI ; <== process ID 0137:0043A0EB FF1574174500 CALL [KERNEL32!ReadProcessMemory];<=== !!!!!!! 0137:0043A0F1 A164E64400 MOV EAX,[0044E664] 0137:0043A0F6 83C002 ADD EAX,02 0137:0043A0F9 A354E64400 MOV [0044E654],EAX 0137:0043A0FE 668B10 MOV DX,[EAX] 0137:0043A101 A164E64400 MOV EAX,[0044E664] 0137:0043A106 83C004 ADD EAX,04 0137:0043A109 52 PUSH EDX 0137:0043A10A 8B542420 MOV EDX,[ESP+20] 0137:0043A10E A354E64400 MOV [0044E654],EAX 0137:0043A113 668B08 MOV CX,[EAX] 0137:0043A116 A164E64400 MOV EAX,[0044E664] 0137:0043A11B 83C006 ADD EAX,06 0137:0043A11E A354E64400 MOV [0044E654],EAX 0137:0043A123 52 PUSH EDX 0137:0043A124 0FB7C9 MOVZX ECX,CX 0137:0043A127 51 PUSH ECX 0137:0043A128 E823FEFFFF CALL 00439F50 ;checks the area at 445000h 0137:0043A12D 8B442428 MOV EAX,[ESP+28] 0137:0043A131 83C40C ADD ESP,0C 0137:0043A134 83C014 ADD EAX,14 0137:0043A137 8B0D60E64400 MOV ECX,[0044E660] 0137:0043A13D 8B542410 MOV EDX,[ESP+10] 0137:0043A141 6A00 PUSH 00 ; <== PCount = 0 0137:0043A143 50 PUSH EAX ; <== Count = 1C5F bytes to write 0137:0043A144 51 PUSH ECX ; <== buffer to read from 0137:0043A145 52 PUSH EDX ; <= address to write to = 445000 0137:0043A146 56 PUSH ESI ; <== process ID 0137:0043A147 FF1570174500 CALL [KERNEL32!WriteProcessMemory] 0137:0043A14D 8B54241C MOV EDX,[ESP+1C] 0137:0043A151 8B3D60E64400 MOV EDI,[0044E660] 0137:0043A157 83C214 ADD EDX,14 0137:0043A15A 33C0 XOR EAX,EAX 0137:0043A15C 8BCA MOV ECX,EDX 0137:0043A15E C1E902 SHR ECX,02 0137:0043A161 F3AB REPZ STOSD 0137:0043A163 8BCA MOV ECX,EDX 0137:0043A165 83E103 AND ECX,03 0137:0043A168 F3AA REPZ STOSB 0137:0043A16A A164E64400 MOV EAX,[0044E664] 0137:0043A16F 50 PUSH EAX 0137:0043A170 E8FB240000 CALL 0043C670 0137:0043A175 83C404 ADD ESP,04 0137:0043A178 8B0D60E64400 MOV ECX,[0044E660] 0137:0043A17E 51 PUSH ECX 0137:0043A17F E8EC240000 CALL 0043C670 0137:0043A184 83C404 ADD ESP,04 0137:0043A187 56 PUSH ESI 0137:0043A188 FF15F0174500 CALL [KERNEL32!CloseHandle] 0137:0043A18E 8B8C247C010000 MOV ECX,[ESP+0000017C] 0137:0043A195 8B842478010000 MOV EAX,[ESP+00000178] 0137:0043A19C 51 PUSH ECX 0137:0043A19D 50 PUSH EAX 0137:0043A19E FF15E0A64400 CALL [0044A6E0] ; <== this leads us right 0137:0043A1A4 83C408 ADD ESP,08 ; to the decoded 0137:0043A1A7 5D POP EBP ; protection scheme! 0137:0043A1A8 5F POP EDI 0137:0043A1A9 5E POP ESI 0137:0043A1AA 5B POP EBX 0137:0043A1AB 81C464010000 ADD ESP,00000164 0137:0043A1B1 C3 RET .....................I think this is clear enough: The firs few Reads are dealing with the "hidden" piece of code - reading and decoding it. The culprite in this scheme is the last Read, just before the final Write: It reads from the area where the code should be placed in and stores it in a buffer in memory (see your help reference for the parameters passed to both functions). Before the Write we have at memory location 00445000 following "code salad":
............... :00445000 AF scasd :00445001 DE00 fiadd word ptr [eax] :00445003 00840E0F001203 add byte ptr [esi+ecx+0312000F], al :0044500A 2415 and al, 15 :0044500C 36 BYTE 036h :0044500D 27 daa :0044500E 3839 cmp byte ptr [ecx], bh :00445010 6A7B push 0000007B :00445012 4C dec esp :00445013 9D popfd ...............But after that:
.............. 0137:00445000 8B442408 MOV EAX,[ESP+08] 0137:00445004 81EC98000000 SUB ESP,00000098 0137:0044500A 3D10010000 CMP EAX,00000110 0137:0044500F 56 PUSH ESI 0137:00445010 740C JZ 0044501E 0137:00445012 3D11010000 CMP EAX,00000111 0137:00445017 7468 JZ 00445081 0137:00445019 E9C5000000 JMP 004450E3 0137:0044501E 8BB424A0000000 MOV ESI,[ESP+000000A0] 0137:00445025 56 PUSH ESI 0137:00445026 E8C5000000 CALL 004450F0 0137:0044502B 83C404 ADD ESP,04 0137:0044502E 56 PUSH ESI 0137:0044502F FF1558194500 CALL [USER32!SetForegroundWindow] 0137:00445035 56 PUSH ESI 0137:00445036 FF155C194500 CALL [USER32!BringWindowToTop] 0137:0044503C A168E64400 MOV EAX,[0044E668] ..............Then the call at
0137:0043A128 E823FEFFFF CALL 00439F50reads the data FROM THE BUFFER and checks it against patches. The same routine uses some of the values there as pointers for further reads so when you change something in the .EXE the program crashes immediately due to an ugly PF. More on, a lot of jump-tables are set among the checks there accordingly to the read piece of code, which are necessary for the proper work of the program.
Preprocessing the targetNow we have to summarize our approach: The idea is that cracking the protection itself should be rather banal and we can leave it for some later point. What we need first is to "fix" the code there and preserve it from the final Write, since it would destroy all our patches. This is a kind of "crack before the crack" which I called Precrack ;-). After that, you can analize it in a more relaxed way, maybe with your favorite cocktail in your hand...
To do this we can crack the check routine itself in order to make it set the jump tables and then bypass the WriteProcessMemory; this would probably work, but there are lots of checks, it would be the hell to trap them and we can never be sure that we have fixed them all.
It is allways better when we have to do with such complex encoding/decoding algorithms to try to fool them, making them believe that everything is OK, while our crack lurks in the background... This decreases the risk of evntl. further side effects too.
In this case I choosed following approach:
First we need of course the binary image of the protection scheme. This is best done with softice - we bpx at WriteProccesMemory and right after it we issue:
d 004450000 L 1C5Fsince we know that the code is already there at this point. Then GO and back in the SoftIce Loader we choose "safe history to file". The hexdump of the memory with the protection is now in some file, p.e. dump.txt by me.
Now comes right the next problem: In the dump we have something like this:
................... :d 445000 L 1cf5 013F:00445000 8B 44 24 08 81 EC 98 00-00 00 3D 10 01 00 00 56 .D$.......=....V 013F:00445010 74 0C 3D 11 01 00 00 74-68 E9 C5 00 00 00 8B B4 t.=....th....... 013F:00445020 24 A0 00 00 00 56 E8 C5-00 00 00 83 C4 04 56 FF $....V........V. 013F:00445030 15 58 19 45 00 56 FF 15-5C 19 45 00 A1 68 E6 44 .X.E.V..\.E..h.D 013F:00445040 00 8D 4C 24 04 50 68 00-AA 44 00 51 E8 9F 77 FF ..L$.Ph..D.Q..w. 013F:00445050 FF 8D 4C 24 10 83 C4 0C-51 68 36 A0 00 00 56 FF ..L$....Qh6...V. 013F:00445060 15 24 1A 45 00 A1 B0 A9-44 00 85 C0 74 75 6A 00 .$.E....D...tuj. 013F:00445070 50 6A 30 68 39 A0 00 00-56 FF 15 FC 18 45 00 EB Pj0h9...V....E.. 013F:00445080 62 66 8B 84 24 A8 00 00-00 66 3D 01 00 75 10 8B bf..$....f=..u.. 013F:00445090 B4 24 A0 00 00 00 56 FF-15 68 19 45 00 EB 44 66 .$....V..h.E..Df ..................but this is still the ASCII representation of the memory content and we need it to be encoded back in bin format. Since no one of the HexEditors known by me offers such a feature like importing ASCII dump (or exporting its screen content to ASCII) we must help us ourself. I did it (once more!) for you this time. I modified the Skeleton program by Barry Kauler from his book Windows Assembly Language and Systems Programming (BTW a very interesting example of programing for windo$e in pure Assembly, you should study it!) by adding a menu item (Convert), a button with tooltip for it, some code to perform the convertion (Convert.asm) and named it Hexer.
When you open a file the hexer reads its content in a buffer and when you press convert it converts it from ASCII dump in binary with consecutive saving it with the extension "bin". The Hexer filters the input, thus throwing any characters that appear not to be a hex digit, otherwise it packs the consecutive hex digits pair-alike in a byte.
However you must strip both columns with the address information and the ASCII dump from your file, leaving this way only the relevant hex part in the middle; the hexer then takes care of the spaces and other non binary characters(-). You need for this a good TextEditor which allows block selecting, the TextPad from Helios is such a tool.
After doing all this you should have a file named XXX.bin which contains the whole protection scheme as it appears in the memory after the Write.
Now lets look for a place for the original code at that location - from 00445000 to 00446C60 (or 44400h to 46060h in the EXE), which, as we know is relevant for the checks before that.
With some experimenting you can see that the routine checks indeed only the non- zeroed part of it, these are 0E8Ah bytes of code - from 44400h to 4528Ah in the exe. From the bottom line in the code window in SoftIce we know that this section is called .etext and with pdump.exe we find out that it is 1E00 bytes long:
............. 02 .etext VirtSize: 00001C4B VirtAddr: 00045000 raw data offs: 00044400 raw data size: 00001E00 relocation offs: 00000000 relocations: 00000000 line # offs: 00000000 line #'s: 00000000 characteristics: 60000020 CODE MEM_EXECUTE MEM_READ .............The Virtual address above concerns the adresses in the process address space - when the program is loaded in memory (at run time), while the RAWs show the ofsets in the EXE file.
For our example we should need 1C4B+E8A=2AD5h bytes which goes beyond the .etext section's border. Right after the .etext is the data section what means that we cannot paste the E8Ah bytes content without destroying the data there.
What to do? Shold we give up?
Not at all! We must simply extend a section to the desired value.
This brings right two other problems: Which section should we extend, and how to adjust the PE header in order for the EXE to be properly loaded after that?
The .etext is the second section and there are still 5 of them, what means, when wee manipulate the size of the .etext we have to adjust all other that comes behind it which would be a hell job. So we look for the LAST section in this executable which happens to be the .reloc one:
............. 07 .reloc VirtSize: 0000572A VirtAddr: 00072000 raw data offs: 0006A800 raw data size: 00005800 relocation offs: 00000000 relocations: 00000000 line # offs: 00000000 line #'s: 00000000 characteristics: 42000040 INITIALIZED_DATA MEM_DISCARDABLE MEM_READ ............As we can see it has 572A bytes initialized data (data we should NOT touch!) and is at offset 6A8000 in the file. With our piece of code the size increases to:
572A+0E8A=65B4hwhat we round up to 6600h (must be so for systems reason) for both virtual and raw size. The offset in the EXE where we should place our code is calculated so:
6A800+572A=6FF2Ahcoze the actual data ordinals in the segment run from 0 to 5729h.
What leaves is the new virtual address that we will pass to the ReadProcessMemory function. We calculate it so:
VirtAddr+OldVirtSize+ImageBase what means: 72000+572A+400000=47772AhWe proceed further so:
We have to adjust the size of the .reloc in order to avoid wrong file format complain by the loader and to make sure the WHOLE new segment will be loaded. For this we open the Pdexplo.exe with the Hexeditor and search for the string ".reloc". There are two occurences, the first in the header, right at the beginning of the exe, and the second where the actual segment starts. We need the first one since there the size and the offset are stored:
.............. 00000260 00 00 00 40 00 00 40 2E 72 65 6C 6F 63 00 00 ....@..@.reloc.. 00000270 2A 57 00 00 20 07 00 00 58 00 00 00 A8 06 00 *W... ...X...... ..............One can easely see where both - virtual and raw - data size are stored (in reverse order!): at 00000270 - Raw Size; and 00000277 - Virtual Size. So we must change them so:
.............. 00000260 00 00 00 40 00 00 40 2E 72 65 6C 6F 63 00 00 00000270 00 66 00 00 20 07 00 00 66 00 00 00 A8 06 00 ..............I didn't adjust the data size coze it runs so, but you can do it if you have any loader problems, you can find it after the PE initials.
Now to the next problem. To make all work properly we must pass our new offset to the ReadProcessMemory. Lets look at the code there:
.............. 0137:0043A0DA 8B542420 MOV EDX,[ESP+20] 0137:0043A0DE A164E64400 MOV EAX,[0044E664] 0137:0043A0E3 8B4C2414 MOV ECX,[ESP+14]; <= address to read from 0137:0043A0E7 52 PUSH EDX 0137:0043A0E8 50 PUSH EAX 0137:0043A0E9 51 PUSH ECX 0137:0043A0EA 56 PUSH ESI = 17 bytes 0137:0043A0EB FF1574174500 CALL [KERNEL32!ReadProcessMemory] ..............You see that the address to read from is passed via the stack. The stack points in this section of code to a region with useful system info about the exe, the hell knows how this data get there! We don't want to crack deeper so we change it to:
............ 0137:0043A0DA 8B542420 MOV EDX,[ESP+20] 0137:0043A0DE A164E64400 MOV EAX,[0044E664] 0137:0043A0E3 52 PUSH EDX ; <== Count, doesn't matter! 0137:0043A0E4 50 PUSH EAX 0137:0043A0E5 682A774700 PUSH 0047772A ; <=== our new location 0137:0043A0EA 56 PUSH ESI = 17 bytes! 0137:0043A0EB FF1574174500 CALL [KERNEL32!ReadProcessMemory] ............and everything will be OK.
You haven't forgotten that we have to bypass the WriteProcessMemory function too, since we don't want it to overwrite our decoded protection with the future cracks there. In the original we have:
............ 0137:0043A141 6A00 PUSH 00 0137:0043A143 50 PUSH EAX 0137:0043A144 51 PUSH ECX 0137:0043A145 52 PUSH EDX 0137:0043A146 56 PUSH ESI 0137:0043A147 FF1570174500 CALL [KERNEL32!WriteProcessMemory] 0137:0043A14D 8B54241C MOV EDX,[ESP+1C] ............which we change to:
............ 0137:0043A141 EB0A JMP 0043A14D 0137:0043A143 50 PUSH EAX 0137:0043A144 51 PUSH ECX 0137:0043A145 52 PUSH EDX 0137:0043A146 56 PUSH ESI 0137:0043A147 FF1570174500 CALL [KERNEL32!WriteProcessMemory] 0137:0043A14D 8B54241C MOV EDX,[ESP+1C] ..........So.
Cracking the targetNow you can start the modified target and if you did everything OK it should present to you its usual screen.
The part with the protection routines is at its native location - 44400h in the exe, 445000 in the Wdasm - and you can crack it as you fancy, I'm not going to do it this time for you! If you are so newbee or so lazy there is on my site the full uvpack.zip: UncleVan's X-mas pack with the listings, the dump.txt and dump.bin files, pedump.exe and "my" version of the Pdexplo.exe.
The other few exe's should v'been protected in a similar manner, you must find out this by yourself. If you find that this is not worth the effort and you still can't life without it you better go to the local airport and carry the baggage of the business class passengers for few hours, then you have the necessary money for buying it ;-)
||I wont even bother explaining you that you should BUY this target program if you intend to use it for a longer period than the allowed one. Should you want to STEAL this software instead, you don't need to crack its protection scheme at all: you'll find it on most Warez sites, complete and already regged, farewell.|
Recapitulation:Which conclusions can we make from this protection?
Well, they are getting better. This target is even harder to crack as some dongle protected ones. We still got the advantage of the assembly and cracking knowledge we obtained from our gurus, but there is only one little step remaining to the modifying "on the fly", I wonder how they didn't make it yet; and they should, if they have read thoroughly enough Reversers page... ;-) the solution is shown there months ago!
Then we will have to do with fully different protection techniques and at the end there will be really "man against man", I see glorious days coming...
That was all for now. I hope you had a nice X-mas and wish you good luck and more cracks in the
(c) UncleVan 1997 All rights reserved
......... But what is this, lo, the proggie is the right versions, but the codes is all wrong. ........I've done it for first in Oct, then when I wrote the essay in mid. November and there were still the same addresses as shown in the essay. The autor hadn't at this time a www page, so we can never be sure which the actual version is. But Squirlle can post me his download ftp and I will take a look at this one.
||Marigold's add-on (16 January 1998)
This is the second part of a very interesting letter by Marigold. The first part deals with Timelock 3 protections and can be read here. I received it on 16 January 1998
I confess now that the real reason to write this letter was the essay by Uncle Van on Mijenix's target. I love Mijenix protections! I cannot forget the acute pleasure their cracking gave me! So, it is jealousy after all... Uncle Van is wrong at least in one point: This program has a history. For +ORC student it is quite a mistake... For me this history began with version 2.0, installed by Pdeval20.exe. I think this version, though obsolete, is still available. Its protection is as follows: application creates a temporary file pdthkxx.tmp, decrypts and writes into it a .dll code. Then it does LoadLibrary and GetProcAddress for all four exported functions in it. Nothing special till now... The real trick is that a call to one of the functions is inside the message loop of the application. And this function contains TranslateMessage and DispatchMessage, so it actually closes the loop (only if all checks are satisfied). What to do? Patching of encrypted DLL's code is unpractical, if only possible... Other calls to protection functions are avoidable and the only real problem is how to close the message loop. So, let's close it! The application itself does not import TranslateMessage and DispatchMessage; thus necessary steps include: 1 GetModuleHandle for USER32, 2 GetProcAddress for TranslateMessage and DispatchMessage, 3 Create a short function which calls them and 4 Redirect call inside a message loop to this new function. PowerDesk Suit includes five executables; in all cases "gross weight" of patching does not exceed ~100 bytes, and we have a lot of space to do it as we do not need now all that protectionists junk which creates and runs temporary DLL. A new generation of Mijenix's products (PowerDesk upgrades to versions 2.0x, ZipMagic 1.0 Trial) uses "improved" protection. Now it does not create a temporary DLL but decrypts a part of application code "in flight". (As rightly described in Uncle's Van essay.) All other features of protection preserved intact! So why shouldn't we use the same solution as before? The installation procedure for PowerDesk upgrade to version 2.0x checks (in its "secret" part) if the previous version is not trial but purchased. If so, it continues (and closes the message loop). So, it is all the same but easier to crack because this application imports TranslateMessage and DispatchMessage (steps 1 and 2 of above are unnecessary here). Patching in this case is only ~20 bytes long. It is longer for two ZipMagic's executables but quite similar. Once having been understood, Mijenix's trick does not look very tough either, but I would rather place it higher than the tricks of TimeLock 3.03. I hope this letter will be of some interest to you. And, please, don't call my favorite approach "brute force". It is not brute, as applications work better after that... they do not need to do many foolish things. Many kisses, Marigold. mari-g(at)usa(point)net
homepage links anonymity +ORC students' essays academy database