crassy
October 23rd, 2002, 02:25
Hi all!
I just found the following tut on a russian site and thought that even you people who don't know Russian (alongside Chinese the best language for a reverser to know) might benefit from the info. So I translated the text... Here it is!
Thanks to the author of the original text!!!
---------------------------------------------------------------------------------
21.10.2002 Armadillo and CopyMem II
Author: Hex
Translated by: Crassy
I don't like unpackers, they make you lazy. Then the author of the unpacker disappears, and thats it. You don't know how it works. This point of view also goes for Armkiller. Therefore I'll describe how to crack Armadillo's decryption with CopyMem II.
Armadillo works like this: it starts two processes:
1) The one that we called. Its like a server.
2) Created by the server (client)
So the server runs the client in debug mode, and when DebugEvents happens it unpacks the client, makes the import etc. and then runs it.
CopyMem II: is a feature of the server. When its enabled the server dynamically decrypts client's code section in blocks of 1000h bytes. After execution of the code of this page it encrypts it again. That means that server watches for page faults, and when they happen decrypts the missing block and puts it in place. So our goal is to force the server to decrypt the whole program and not encrypt it any more.
Tools: Softice, IDA.
As an example I take Armadillo 2.61 Public build 2000 itself. It's the latest version atm and uses CopyMem II.
We disassemble Armadillo 2.61 with IDA. Then we run Armadillo, click "Basic" and don't do anything more.. Now we put bpx Writeprocessmemory and click "Protection" - "Edit Project". SoftIce pops up. We do bd * and press F12 3 times. We see this (I've put some comments in):
The code from _text1:0044D6BF to _text1:0044D74D is just the calculation of codes for decryption of the given page.
To decrypt a page we have to, after execution of
put the number of the desired page into and jump to
In this way we can write a small loop to decrypt all pages right there in SoftIce.
How are page numbers used?
Page number *1000+401000 = address where the decrypted piece is put. So to find out how many pages there are we look at the PE:
Rva of section .text = 1000, Rva of the next section (.rdata) = 2A000 ie the number of pages = ((2A000 - 1000 ) / 1000) - 1 = 28h pages (I found out -1 by trial and error
)
But before writing a loop we have to consider one more detail: Inside ArmaCryptDecrypt there are two different calls of the same procedure:
One:
Two:
The first one always decrypts, while the second one encrypts and removes the page from memory (ie sets No_access).
We do not need it to remove the page at all, Therefore we leave only the first call. The second one happens only if
doesn't jump.
Therefore to decrypt the code section we need to patch
to
and the write the loop I mentioned earlier. Then we dump the decrypted code section.. Easiest way to find OIP is to set BPX SetProcessWorkingsetSize and after 20 lines there is OEP. Then we make a dump at the OEP, and put the code section into it. We restore the import (best under NT/2k, but there shouldn't be any problems in Win98). And work with the rest of the licensing...
What more is there to say... If we look at addresses 44D60B and 44D57B we see the same pieces of code with two differences:
and
So before decrypting a new page it encrypts the previous and the next one. In Armadillo 2.61 Public build 2000 its not used, but it's good to know.
I just found the following tut on a russian site and thought that even you people who don't know Russian (alongside Chinese the best language for a reverser to know) might benefit from the info. So I translated the text... Here it is!
Thanks to the author of the original text!!!
---------------------------------------------------------------------------------
21.10.2002 Armadillo and CopyMem II
Author: Hex
Translated by: Crassy
I don't like unpackers, they make you lazy. Then the author of the unpacker disappears, and thats it. You don't know how it works. This point of view also goes for Armkiller. Therefore I'll describe how to crack Armadillo's decryption with CopyMem II.
Armadillo works like this: it starts two processes:
1) The one that we called. Its like a server.
2) Created by the server (client)
So the server runs the client in debug mode, and when DebugEvents happens it unpacks the client, makes the import etc. and then runs it.
CopyMem II: is a feature of the server. When its enabled the server dynamically decrypts client's code section in blocks of 1000h bytes. After execution of the code of this page it encrypts it again. That means that server watches for page faults, and when they happen decrypts the missing block and puts it in place. So our goal is to force the server to decrypt the whole program and not encrypt it any more.
Tools: Softice, IDA.
As an example I take Armadillo 2.61 Public build 2000 itself. It's the latest version atm and uses CopyMem II.
We disassemble Armadillo 2.61 with IDA. Then we run Armadillo, click "Basic" and don't do anything more.. Now we put bpx Writeprocessmemory and click "Protection" - "Edit Project". SoftIce pops up. We do bd * and press F12 3 times. We see this (I've put some comments in):
Code:
_text1:0044D6BD push 0 ; EnCryptBit - 1 - encrypt, 0 - decrypt
_text1:0044D6BF mov esi, [ebp+PageNumber]
_text1:0044D6C5 shl esi, 4
_text1:0044D6C8 mov eax, [ebp+PageNumber]
_text1:0044D6CE and eax, 80000007h
_text1:0044D6D3 jns short loc_0_44D6DA
_text1:0044D6D5 dec eax
_text1:0044D6D6 or eax, 0FFFFFFF8h
_text1:0044D6D9 inc eax
_text1:0044D6DA
_text1:0044D6DA loc_0_44D6DA: ; CODE XREF: sub_0_44C5FD+10D6j
_text1:0044D6DA xor ecx, ecx
_text1:0044D6DC mov cl, byte ptr ds:unk_0_4591E0[eax]
_text1:0044D6E2 mov edx, [ebp+PageNumber]
_text1:0044D6E8 and edx, 80000007h
_text1:0044D6EE jns short loc_0_44D6F5
_text1:0044D6F0 dec edx
_text1:0044D6F1 or edx, 0FFFFFFF8h
_text1:0044D6F4 inc edx
_text1:0044D6F5
_text1:0044D6F5 loc_0_44D6F5: ; CODE XREF: sub_0_44C5FD+10F1j
_text1:0044D6F5 xor eax, eax
_text1:0044D6F7 mov al, byte ptr ds:unk_0_4591E1[edx]
_text1:0044D6FD mov edi, ds:dword_0_456238[ecx*4]
_text1:0044D704 xor edi, ds:dword_0_456238[eax*4]
_text1:0044D70B mov ecx, [ebp+PageNumber]
_text1:0044D711 and ecx, 80000007h
_text1:0044D717 jns short loc_0_44D71E
_text1:0044D719 dec ecx
_text1:0044D71A or ecx, 0FFFFFFF8h
_text1:0044D71D inc ecx
_text1:0044D71E
_text1:0044D71E loc_0_44D71E: ; CODE XREF: sub_0_44C5FD+111Aj
_text1:0044D71E xor edx, edx
_text1:0044D720 mov dl, byte ptr ds:unk_0_4591E2[ecx]
_text1:0044D726 xor edi, ds:dword_0_456238[edx*4]
_text1:0044D72D mov eax, [ebp+PageNumber]
_text1:0044D733 cdq
_text1:0044D734 mov ecx, 1Ch
_text1:0044D739 idiv ecx
_text1:0044D73B mov ecx, edx
_text1:0044D73D shr edi, cl
_text1:0044D73F and edi, 0Fh
_text1:0044D742 add esi, edi
_text1:0044D744
_text1:0044D744 DeCrypting:
_text1:0044D744 mov edx, ds:dword_0_459A74
_text1:0044D74A lea eax, [edx+esi*4]
_text1:0044D74D push eax ; hHash
_text1:0044D74E mov ecx, [ebp+PageNumber]
_text1:0044D754 push ecx ; PageNumber - number of page to decrypt.
_text1:0044D755 call ArmaCryptDecrypt
_text1:0044D75A add esp, 0Ch
_text1:0044D75D and eax, 0FFh
_text1:0044D762 test eax, eax
_text1:0044D764 jz short loc_0_44D770
The code from _text1:0044D6BF to _text1:0044D74D is just the calculation of codes for decryption of the given page.
To decrypt a page we have to, after execution of
Code:
_text1:0044D75A add esp, 0Ch
put the number of the desired page into
Code:
[ebp+PageNumber]
Code:
_text1:0044D6BD push 0
In this way we can write a small loop to decrypt all pages right there in SoftIce.
How are page numbers used?
Page number *1000+401000 = address where the decrypted piece is put. So to find out how many pages there are we look at the PE:
Rva of section .text = 1000, Rva of the next section (.rdata) = 2A000 ie the number of pages = ((2A000 - 1000 ) / 1000) - 1 = 28h pages (I found out -1 by trial and error

But before writing a loop we have to consider one more detail: Inside ArmaCryptDecrypt there are two different calls of the same procedure:
One:
Code:
_text1:0044E3FF push 0 ; Decrypt...
_text1:0044E401 mov ecx, [ebp+hHash]
_text1:0044E404 push ecx
_text1:0044E405 mov edx, [ebp+PageNumber]
_text1:0044E408 push edx
_text1:0044E409 call Crypting
_text1:0044E40E add esp, 0Ch
Two:
Code:
_text1:0044E48F push 1 ; Crypt...
...............
_text1:0044E542 mov edx, ds:dword_0_459A74
_text1:0044E548 lea eax, [edx+esi*4]
_text1:0044E54B push eax ; Crypting...
_text1:0044E54C mov ecx, ds:dword_0_459A88
_text1:0044E552 mov edx, ds:dword_0_459A8C
_text1:0044E558 mov eax, [edx+ecx*4]
_text1:0044E55B push eax
_text1:0044E55C call Crypting
_text1:0044E561 add esp, 0Ch
The first one always decrypts, while the second one encrypts and removes the page from memory (ie sets No_access).
We do not need it to remove the page at all, Therefore we leave only the first call. The second one happens only if
Code:
_text1:0044E47C jle loc_0_44E57C
doesn't jump.
Therefore to decrypt the code section we need to patch
Code:
_text1:0044E47C jle loc_0_44E57C
to
Code:
_text1:0044E47C jmp loc_0_44E57C
and the write the loop I mentioned earlier. Then we dump the decrypted code section.. Easiest way to find OIP is to set BPX SetProcessWorkingsetSize and after 20 lines there is OEP. Then we make a dump at the OEP, and put the code section into it. We restore the import (best under NT/2k, but there shouldn't be any problems in Win98). And work with the rest of the licensing...
What more is there to say... If we look at addresses 44D60B and 44D57B we see the same pieces of code with two differences:
Code:
_text1:0044D57B push 1 - Encrypt!
...............
_text1:0044D5E8 mov eax, [ebp+PageNumber]
_text1:0044D5EE sub eax, 1 - Previous page
_text1:0044D5F1 push eax ; PageNumber
_text1:0044D5F2 call ArmaCryptDecrypt
and
Code:
_text1:0044D60B push 1 - Encrypt!
.........................
_text1:0044D678 mov eax, [ebp+PageNumber]
_text1:0044D67E add eax, 1 - Next page
_text1:0044D681 push eax ; PageNumber
_text1:0044D682 call ArmaCryptDecrypt
So before decrypting a new page it encrypts the previous and the next one. In Armadillo 2.61 Public build 2000 its not used, but it's good to know.
