-
-
XtremeProtector 1.07
-
发表于: 2004-10-8 19:31 5348
-
机器翻译http://www.cracklab.ru/art/index.php?action=read&id=278的结果。
The author: dragon <c_dragon@mail.ru>
1. Analytics (beginning)
Protectors as well as can be divided(shared) many other things into three categories on a level of protection of the program - low end, middle end and high end. To low end it is possible to attribute(relate) all simple packers such as UPX, ASPack, and also some protectors. To middle end such things, as ASProtect, Armadillo, Obsidum undoubtedly concern, etc. And among high end, i.e. the most powerful protectors it is known only two - XtremeProtector and StarForce. Them very good antidebugging (especially it concerns XProtector'á, try it(him) to start if in system costs(stands) softice), rather quite good protection of import, concealment of a program code which to not receive so simply as it can be made with copymem II in Armadillo distinguishes, and the most important - use Ring0 of a code which most strongly complicates research.
It is possible to allocate two ways of removal of protectors. The first - research in a forehead from a point of an input(entrance) up to OEP and a spelling automatic распаковщика. The second - manual unpacking with the help of a presence(finding) and use of "rear entrances" in a code of a protector, with the purpose of removal дампа, presence(findings) OEP, receptions of import and. т. д. At unpacking XProtector'á we shall go естесственно in the second way as it in any case is easier and faster.
2. The small description of protection
As the purpose it will be used XtremeProtector 1.07 DEMO which is accessible on an official site of the manufacturer. At the moment of a spelling of clause(article) version 1.08 is accessible already, but she(it) is protected worse, therefore in clause(article) and will be described 1.07.
Before perusal it is recommended to understand a little the protected mode and device Windows NT, in particular in a nucleus. Without it it will be difficult to understand, how protection works. As to tools the basic will be IDA versions not ancient 4.50. Also editor PE of files (PE Tools recommended), ImpRec, the hexadecimal editor (WinHex), and also package MASM32 will be necessary. Also it is necessary to establish the plug-in - emulator x86 for IDA (it is accessible on wasm.ru) and a plug-in for clearing from scrambled a code (is in archive accompanying clause(article)). All right, now it is possible to proceed(pass) directly to the description.
So, protection will consist of two parts, the most packed program and the driver under a name xprotector.sys which lays in the catalogue \System32\Drivers. During the certain moment of work the code of a protector causes function DeviceIoControl with a code 1800h at which processing the driver carries out(spends) some initialization. We look, that it(he) there does(makes):
Defines(Determines) number of processors in system
Finds IDT address for each processor and resolves access to IDT from the user mode at a level of pages
Opens access to the first page with the data where there is a file with IDT addresses
Opens access to all ports of input-output
In most cases IDT there will be certainly one, only in case of the multiprocessing machine or Pentium IV HT tables of interruptions will be more one though it does not affect unpacking in any way. And that the code of a protector gets direct access in ring0 affects and can do(make) that wants. And it(he) wants that, for example that it(him) did not debug and not дампили much. In fact it is valid, to the started program it will not be risen, attempt сдампить from PE Tools leads to to the message on impossibility of reading of memory of process. If to start softice the appendix is closed and if приаттачится to process Ollydbg will be in general перезагрузка. First of all it is necessary to liquidate антидамповую protection and antidebugging, and then already to think, what to do(make) further
3. Removal антидамповой and antidebugging protection
It is obvious, that if memory is accessible to reading from one process and inaccessibl from another are intercepted API functions for work with memory. We start to look a code of function ReadProcessMemory from kernel32.dll. Apparently interceptions it is not observed. Also them it is not observed and in native api functions NtReadVirtualMemory. Further already a nucleus. As management gets on corresponding function in nucleus WinNT is well described in second clause(article) about packers on wasm.ru. The first where it is necessary to look so it in system service table or is shorter sst - the table of addresses of functions ntoskrnl.exe. For this purpose in archive utility R0cmd.exe and the driver lays. With its(her) help it is possible дампить and to load IDT, SST, SST shadow for ntoskrnl.exe and win32k.sys and in general any sites of memory in the field of a nucleus. For definition of interception it is possible to compare two дампа sst - before start XProtector'á and the ambassador. Tables differ, means XProtector контроллирует some functions ntoskrnl. To find out, what it is functions, displacement отличающися elements in дампе is necessary to divide on 4 and to find number in a file of Zw-functions from library ntdll.dll. In result we have the list of the intercepted functions:
NtAllocateVirtualMemory
NtCreateThread
NtQueryVirtualMemory
NtReadVirtualMemory
ZwTerminateProcess
NtWriteVirtualMemory
The maintenance(contents) of these functions to result there is no sense, there at attempt of access from other process to the protected program the error code comes back. Also it is blocked дамп with the help removed треда (CreateRemoteThread). But most surprising it that the ambassador in обработчике ZwTerminateProcess is not restored neither sst nor idt. Probably the protector has climbed somewhere else, it is probable in the scheduler of streams. I give to check up it that who well understands nucleus WinNT. We here are interested with removal антидампа more. It is obvious, that it(him) to remove(take off), there is enough подгрузить on a place the normal table sst by means of same utility R0cmd. And now it is possible to use such utilities, as PE Tools and ImpRec. But here it is impossible while to use a debugger.
R0cmd/viewidt:??? - allows to look IDT in a text kind. Attention the cut down debugging interruptions int1 and int3 (their address began 0FFFFFFFFh) at once draw. All would seem simply, has restored IDT yes debug, but leaves nothing. At attempt to restore IDT the program or is cut down, or IDT comes back to an initial condition. The matter is that the superfluous streams generated by a protector which check IDT. But though the protected program to debug it is impossible, but it is possible to debug other programs. How it is possible? And here is how, by a call int1 or int3 management gets on 0FFFFFFFFh address, memory to this address usually is not present, therefore there is exception Page fault (*PF), обработчик which too is intercepted. Clearly, that in it(him) also there is a processing of any debugging actions of the user. It is necessary to result his(its) code обработчика:
seg000:F8AB8000 pushf
seg000:F8AB8001 pusha
seg000:F8AB8002 call $ +5
seg000:F8AB8007 pop ebp
seg000:F8AB8008 sub ebp, 1E09229h
seg000:F8AB800E inc dword ptr [ebp+1E0925Fh]
seg000:F8AB8014 cmp dword ptr [ebp+1E0925Fh], 63h
Transition will be executed at overflow of the counter therefore
on a place of int1/int3 addresses in IDT will be written down 0FFFFFFFFh, it is
not especially interesting seg000:F8AB801B ja loc_F8AB80B0
seg000:F8AB8021
seg000:F8AB8021 loc_F8AB8021:; CODE XREF: sub_F8AB8000+128
And here that comparison EIP with 0FFFFFFFFh is necessary, means we go on пореходу on F8AB8041
seg000:F8AB8021 mov eax, [esp+28h]
seg000:F8AB8025 cmp eax, 0FFFFFFFFh
seg000:F8AB8028 jz short loc_F8AB8041
--------------------------------------------------------------------------------
seg000:F8AB8041 loc_F8AB8041:; CODE XREF: sub_F8AB8000+28
seg000:F8AB8041 mov eax, 1
seg000:F8AB8046 mov ecx, eax
seg000:F8AB8048 or eax, eax
Well is not present, that it is simple jmp to write..
seg000:F8AB804A jnz loc_F8AB8138
--------------------------------------------------------------------------------
seg000:F8AB8138 push fs
seg000:F8AB813A mov eax, 30h; the selector for the register fs in a nucleus - 30h
seg000:F8AB813F db 66h
seg000:F8AB813F mov fs, ax
;We receive the index on structure KTHREAD (or ETHREAD)
seg000:F8AB8142 mov eax, large fs:KPRCB.CurrentThread
;And it is the index on KPROCESS, it(he) the index on object of
process seg000:F8AB8148 mov eax, [eax+KTHREAD.ApcState. Process]
seg000:F8AB814B pop fs
seg000:F8AB814D mov ebx, eax
seg000:F8AB814F and ebx, 7FFFFFFFh
;Probably to this address or hardly the index on object
protected XProtector'ом process, if it(he) current, or a constant 47616420h if is not present further enters
the name.
All this probably occurs in a code of switching of
streams seg000:F8AB8155 mov esi, 0F8AB6000h
seg000:F8AB815A cmp dword ptr [esi], 0
seg000:F8AB815D jz loc_F8AB8075
seg000:F8AB8163
seg000:F8AB8163 loc_F8AB8163:; CODE XREF: sub_F8AB8000+17A
seg000:F8AB8163 add esi, 4
seg000:F8AB8166 cmp dword ptr [esi], 47616420h
Ага, transition to a call old обработчика interruptions if process is not protected.
seg000:F8AB816C jz short loc_F8AB8187
seg000:F8AB816E cmp [esi], eax
And further transitions not there where it is necessary, and they are carried out, if
*PF has taken place in the protected process
seg000:F8AB8170 jz short loc_F8AB817C
seg000:F8AB8172 cmp [esi], ebx
seg000:F8AB8174 jz loc_F8AB8075
seg000:F8AB817A jmp short loc_F8AB8163
It is obvious, that if пропатчить transition to the address F8AB816C (In general that it(he) can be and another, the main thing, that this address is calculated as *PF+16Ch. In the programs protected XProtector'ом 1.08 displacement will be 17A). Патчить the nucleus without special tools is impossible, but possible to take advantage again R0cmd. For this purpose it is necessary to create a file in the size of 1 byte and to write down in him(it) EB, and then to load, using a command(team)/load. After restoration sst and a patch обработчика *PF debugging with help Ring3 of debuggers, for example Ollydbg becomes possible(probable). On softice to expect it is not necessary, too a lot of attention was given it(him) by developers.
4. Restoration of import and presence(finding) OEP
Now we start traditional enough things in unpacking - to import and OEP. For presence(finding) OEP it will be described the whole two ways, but for one of them it is required распалогать by some information, namely the address of procedure of decoding of blocks of a code which to learn(find out) it is not obviously possible yet. Therefore for the beginning a way such: we find the table with adapters on imported functions, and instead of the present(true) transitions to write down there transitions to function which shall tell shows in MessageBox'Ñ the address of the call. It is obvious, that this address will be is close to OEP. It are necessary to find only the table of these transitions and пропатчить her(it). To find the table, problems do not arise, simply it is necessary to look through a code for calls of procedures and to look, where it(he) conducts. It is visible, that the table of transitions begins to the address 439850h and comes to an end on 439AF0h address And here so that пропатчить, problems is greater. Way such, we create process with the frozen stream (flag CREATE_SUSPENDED in соотв. Parameter), then using API CreateRemoteThread with the address of the removed stream equal to the address of function LoadLibraryA and the parameter equal to a name introduced DLL it is loaded this the most introduced DLL in address space of the protected program. The name естесственно should be registered beforehand with the help of pair functions VirtualAllocEx and WriteProcessMemory. All this is shown in a source code. Now DLL will receive notices on loading in address space of process, creation of a stream, и.т.д. The most such obvious way - to use a multithreading of a code of a protector, i.e. to wait creations of last stream, and during processing the notice to alter all this table of transitions under the needs, but XProtector not so it is simple, it(he) of it does not allow (If in the table changes the protector will change transitions once again, one change to it(him) will be appreciable appears a little). The output(exit) in that all this to do right after fillings of this table, and is even better during its(her) creation. Now this code is necessary for finding somehow. It very much is useful and at restoration of import since other opportunities well in any way do not approach. Reduction of a code of adapters the order and serial comparison with exported functions - is too difficult, and the variant to palm off instead of functions push XXXXXXXX/ret does not pass adapters of a kind, the protector notices it and is cut down.
If присмотрется to addresses of adapters it is possible to notice, that they are in the allocated virtual memory with which it is possible to allocate with function VirtualAlloc. Now is farther, depending on version Windows the size of code API of functions different, allocation of memory means occurs directly in procedure of creation of import. The output(exit) means in catching calls of this API. Basically at a protector all is seized, patch API is direct kernel32.dll will not help, since she(it) is read directly from a disk in memory, processed, and functions therefrom are caused. In a nucleus to climb too uneasily, the idealest place for interception - Zw-functions means. Function ZwAllocateVirtualMemory necessary to us (I Hope in Microsoft will not take offence, in fact it is forbidden to spread source codes Windows) here is how looks:
.text:77F75832 public ZwAllocateVirtualMemory
.text:77F75832 ZwAllocateVirtualMemory proc near
.text:77F75832 mov eax, 11h
.text:77F75837 mov edx, 7FFE0300h
.text:77F7583C call edx
.text:77F7583E retn 18h
.text:77F7583E ZwAllocateVirtualMemory endp
Simply we change the instruction to the address 77F75837 so that in the register edx обработчика address of the intercepted procedure which, say, collects all addresses calls VirtualAlloc in a file was. To receive the address of call VirtualAlloc it is possible, having read it(him) from a stack. Displacement is relative esp can be found out, having debugged the program causing VirtualAlloc. In Windows XP SP1 this displacement is equal 68h. At unloading DLL contents of this file can be thrown off in a file, as well as it is made in a source code on restoration of import.
The address which should draw attention - 7E0B0Eh since at return on this address memory which addresses very much remind addresses of adapters is allocated. From him(it) also it is necessary to dig all procedure. Here I shall result only the most interesting moments in this procedure. Here for example a small piece of a code which keeps displacement after опкода 0E9 (long jmp):
XPROT ___:007E0C21 lStoreJumpToImportFunction:; CODE XREF: XPROT ___:007E0C05
XPROT ___:007E0C21; XPROT ___:007E0C10
;edi - the address on which there is this displacement
XPROT ___:007E0C21 mov eax, [ebp+AddressOfImportFunction]
XPROT ___:007E0C27 sub eax, edi
XPROT ___:007E0C29 sub eax, 4
XPROT ___:007E0C2C stosd
For the beginning it will suffice us, we change the instruction mov eax, [ebp+AddressOfImportFunction] for something like mov eax, offset import_accepted. To change it is necessary after first interception ZwAllocateVirtualMemory with the required address of return from VirtualAlloc. And again we are waited with a surprise, namely one bad MessageBox with the message " An Error has ocurred while loading imports ". Certainly no mistake can be, and here check of integrity of a code of procedure very much even can. Looking through a code of creation of procedure is farther, I was involved with the following code:
XPROT ___:007E0737 pusha
XPROT ___:007E0738 lea esi, [ebp+BeginProtectedArea]; 007E046F - the beginning of
procedure XPROT ___:007E073E lea edi, [ebp+EndProtectedArea]; 007E12F9 - and the end of
procedure XPROT ___:007E0744 sub edi, esi
XPROT ___:007E0746 mov edx, edi; edx - length of checked code
XPROT ___:007E0748 mov edi, [ebp+1D70619h]
XPROT ___:007E074E or ecx, 0FFFFFFFFh
XPROT ___:007E0751
XPROT ___:007E0751 hash_loop:; CODE XREF: XPROT ___:007E0761
XPROT ___:007E0751 xor eax, eax
XPROT ___:007E0753 mov al, [esi]
XPROT ___:007E0755 xor al, cl
XPROT ___:007E0757 inc esi
XPROT ___:007E0758 mov eax, [edi+eax*4]
XPROT ___:007E075B shr ecx, 8
XPROT ___:007E075E xor ecx, eax
XPROT ___:007E0760 dec edx
XPROT ___:007E0761 jnz hash_loop
XPROT ___:007E0767 mov eax, ecx
XPROT ___:007E0769 not eax
XPROT ___:007E076B cmp [ebp+ValidHashValue], eax; Here and comparison..
XPROT ___:007E0771 jz loc_7E0781; well here conditional transition.
XPROT ___:007E0777 mov dword ptr [ebp+1D71831h], 1
XPROT ___:007E0781
XPROT ___:007E0781 loc_7E0781:; CODE XREF: XPROT ___:007E0771
XPROT ___:007E0781 popa
Made unconditional transition to the address 007E0771h will resolve any updatings in procedure of creation of import, that very much even it is good. For example it allows a program - example to display rather humiliating окошко with an inscription " dump me!!! " And heading OEP near 42A37Ah. And it is valid OEP lays absolutely beside, to the address 42A373h. But the address on which it is transferred managements after working off of a code of a protector is little bit above, it is connected to protection of a code about(near) OEP, details will be considered below when it will be told about protection of a code.
Now we shall engage in reception of addresses of imported functions that it was possible using imprec, to restore a directory of import. Since functions kernel32, user32 and advapi32 there should be a group of comparisons and transitions which should be found and corrected are protected only. I think for этогол such group will leave:
XPROT ___:007E08A9 loc_7E08A9:; CODE XREF: XPROT ___:007E0828 j;
As on a palm four transitions which editing will lead to to the pure(clean) table lay;
import and the table of transitions (is more true almost pure(clean), one function nevertheless придёться to distinguish
manually;
in this case this function - GetStartupInfoA
XPROT ___:007E08A9 cmp dword ptr [ebp+1D70A05h], 1
XPROT ___:007E08B0 jz lScrambled0
XPROT ___:007E08B6 cmp ecx, [ebp+BaseOfKernel32]
XPROT ___:007E08BC jz lScrambled0
XPROT ___:007E08C2 cmp ecx, [ebp+BaseOfUser32]
XPROT ___:007E08C8 jz lScrambled0
XPROT ___:007E08CE cmp ecx, [ebp+BaseOfAdvapi32]
XPROT ___:007E08D4 jz lScrambled0
XPROT ___:007E08DA
XPROT ___:007E08DA lNoScrambled:; CODE XREF: XPROT ___:007E08FD
XPROT ___:007E08DA; XPROT ___:007E0922...
XPROT ___:007E08DA lea ebx, [ebp+GetProcAddressX0]
XPROT ___:007E08E0 call ebx
XPROT ___:007E08E2 mov edi, eax;
Here all is simple, the correct address of function enters the name and is transferred somewhere;
Further - on creation of transition and element IAT. Management should get here
XPROT ___:007E08E4 mov [ebp+AddressOfImportFunction], eax
XPROT ___:007E08EA jmp loc_7E0B4A
Having replaced each transition by six instructions nop we achieve creation of the pure(clean) table of import and transitions. To find IAT here it is not difficult, it is necessary to look only field Base Of Data in PE heading, usually the table of import there and lays. Now at last it is possible to restore import, but неободимо also to reorient transitions in the table that they specified elements IAT instead of in emptiness. For this purpose in archive the small utility also lays. After all it it is possible to tell, that the first stage of unpacking is completed, but XtremeProtector also has taken care of protection of the code. It is necessary to work further receiving all code in an open kind.
5. Protection of a code of a protector, scrambled a code
As there will be an active research of a code of a protector it is necessary to tell a little that prevents his(its) research longer. First of all it is a scrambled-code, i.e. a code which is strongly diluted with dust. I bring some kinds of dust below:
--------------------------------------------------------------------------------
push eXX
push eXX...
sidt
[esp - 2]; Kept IDT address is
not used...
pop eXX...
pop
eXX
--------------------------------------------------------------------------------
push eax
push edx...
rdtsc;
Reading of the counter of steps of the processor, also is
not used...
pop edx...
pop
eax
--------------------------------------------------------------------------------
pusha...
popa
--------------------------------------------------------------------------------
Also there are senseless conditional and unconditional transitions, instructions of a kind mov eax, eax. Except for a scrambled-code also there are designs of the following kind:
--------------------------------------------------------------------------------
push eXX
call proc0
db 0XXh; Garbage byte
jmp [esp - 0Ch]
proc0:
pop eXX
mov [esp-8], eXX;
displacement concerning "garbage" байта Here increases,
management
add [esp-8], 20h
inc eXX there is then transferred; Detour garbage байта
push eXX
retn
--------------------------------------------------------------------------------
Try потрассировать on F8 such code in Softice and will see something strange, instructions jmp [esp-0Ch] are farther to pass will fail, who it can can explain?
Is present as well such code (deciphering ahead a double word):
push ebx
push edx
push edx; Registers естесственно can be and others
sidt [esp - 2]
;Usually in ebx it turns out 0Ch or 1Ch, that corresponds(meets) to displacement of parameters int1 or int3 in IDT
mov ebx, XXXXXXXX
xor ebx, XXXXXXXX; Instead of xor there can be other arithmetic instruction
pop edx
add edx, ebx
;The key is written directly in IDT, all the same debugging interruptions are
cut down mov dword ptr [edx], XXXXXXXX
mov edx, [edx]
call $ +5
pop ebx
add ebx, XX
xor [ebx], edx; Decoding of a part of a code ahead...
xor
[ebx], edx; Here restoration for an opportunity of repeated execution(performance) of
a code push 0FFFFFFFFh
;There обработчиков int1 addresses and int3 become equal to the transmitted parameter
call proc0
pop edx
pop ebx
This code also is diluted with a significant amount of garbage instructions.
Also it is necessary to mention two kinds ring0-дишифровщиков a code. They are too complex(difficult), therefore their code I shall not result. The plug-in for IDA in archive allows to replace the most widespread scrambled-code with group nop'ов, and supports one of ring0-дешифровщиков. It(he) strongly facilitates research, in fact scrambled the code meets in the procedures responsible for decoding of a code, the driver xprotector.sys, and it is a lot of where still.
6. Full restoration of a code of the program
Received in the previous steps дамп it is not started at all, a mistake, which reason - too much an absent code which now and we shall restore at once gives out. The first, than costs(stands) занятся, so it подгрузить отсутсвующий a code which sites are obviously visible in PE Tools in an option dump region. Something similar on CopyMem II in Armadillo, but only with that difference, that process one, and exceptions processes a code of a protector. One more difference from CopyMem II - sites of a code are deciphered at attempt of performance, instead of at attempt of any access to memory. The way of decoding is easy enough, we transfer management to such site of memory, and the protector after processing exception should cause in any case function ZwContinue for продолженя performance. The first and unique parameter at it(her) - the index on structure CONTEXT. That management was not transferred further, it is necessary to intercept simply her(it) in the same way, as ZwAllocateVirtualMemory at creation of import and to reorient EIP for the subsequent execution(performance) of a cycle. The received pieces of a code (all in the size 2000h, i.e. two pages) to put(fold) in the allocated(removed) area of memory, and after the termination(ending) of a cycle simply to resolve access to memory and to copy them on a place. Such way also is used in a source code. All this to make it is necessary, because XProtector at opening one pair pages, can close another.
There are also three more designs for protection of a code, shall consider all over again designs, and then ways of reception of a code.
call XXXXXXXX; the Address of procedure of decoding, in this case - 7DC1BBh
dd 0XXh; the Identifier of a stream which all this will
decipher dd 0; 0 - decoding, 1 - an
encryption dd 0XXh; length of
a code db 06Fh; garbage byte...-;
Further the ciphered code.
The finishing part can will be distinguished. If the ciphered code is carried out only once, it(he) затирается by zero:
pusha
call $ +5
pop edi
sub edi, 0XXh
mov ecx, 0XXh; Here and above 0XXh - length of the ciphered code increased on 1
xor eax, eax
rep stosb
popa
And here if the code is executed repeatedly from such затирания anything good will not leave, therefore end of a code such:
call XXXXXXXX; the Address of procedure of enciphering of a code - another, here it(he) is equal 007C0D1Bh
dd 0XXh
dd 1
dd 0XXh
db 06Fh
The principle of action of these procedures consists in filling variables with the data on the address, length, и.т.д. Then procedure causes function SetEvent and is started up in an infinite cycle jmp eax. The deciphering stream fulfils and transfers management to the deciphered code by means of an adapter. Теоритически besides to change EIP in the other stream call SetThreadContext is necessary. All again solves interception native api, this time ZwSetContextThread. It is enough to change EIP for the adapter and to continue a cycle of restoration of a code since it(he) remains in an open kind. Designs such should be found direct search, better and to not think up. Also it is necessary to provide cleaning of a code from calls and parameters of encryption / decoding of a code and replacement in his(its) zero. Now we pass further.
By consideration of procedure of creation of import it was possible to notice, that instead of function wsprintfA its(her) real address, and at all(even not) a scrambled-adapter, and any suspicious code is put not. And in the code of the program there are not less suspicious calls wsprintfA strange parameters. Work of this function it is possible to observe under a debugger, or, that it is easier, under the emulator x86 in IDA. To result here details there is no sense since to decipher the sites of a code opened by this function simply elementary - transfer(pass) management on such call and change the address of return. These calls also are necessary for cleaning, as an opening call:
push 78263845h;
All XX - parameters of
decoding push XX
push 0; 0 - an opening call, decoding of
a code push XXXXXXXX
push XXXXXXXX;
78263845h is a constant ('x*8E' or 'E8*x'), on it(her);
обработчик wsprintfA learns(finds out), that it is necessary to do(make) - to pass on real wsprintfA;
or to decipher a
code push 78263845h
call XXXXXXXX; обработчика wsprintfA Address (the address of transition jmp on him(it) is more exact)
And closing:
push 78263845h
push XX
push 1; 1 - a closing call, enciphering of
a code push XXXXXXXX
push XXXXXXXX
push 78263845h
call XXXXXXXX
And at last last most complex(difficult) stage - restoration of a stolen code, and it(him) steal not on OEP, and on all section of a code. It is done(made) such with the help sdk XProtectora for protection of any important sites of a code, we shall tell checks of the entered password.
All these protection of a code are found out at attempt of start of the unpacked program with cut off section XPROT. Here for example we shall try to open a file for protection, the program will take off on 435569h address on wrong опкоде. Here general structure of such protection of a code:
jmp invalid_opcode
db "xpro" It simply the
signature dd 00 - the beginning, 1 - the termination(ending).
dd 0
db "xpro"
invalid_opcode:...
Anyone опкод, causing the sixth exception (invalid opcode)
At the end of this site there is the same, only with unit instead of zero. For reception of a code придёться to look, where management after processing exception gets. It appears, that EIP varies, and management is transferred somewhere far in virtual memory. We shall look, that there such. The beginning does not represent anything interesting, expectation of occurrence of the two to the address 2F103CCh is simple. Decoding laying ahead of a code (the code resulted below is processed by a plug-in from archive) further begins:
seg007:02F10039 call loc_2F1004F; the Beginning of
decoding seg007:02F10039;---------------------------------------------------------------------------seg007:02F1003E
db 75h, 0Ah, 7Bh, 98h, 0F1h, 0D6h, 57h, 44h, 2Dh, 62h
seg007:02F1003E db 0F3h, 0B0h, 29h, 0AEh, 4Fh, 0DCh, 0E5h
seg007:02F1004F;---------------------------------------------------------------------------seg007:02F1004F
seg007:02F1004F
loc_2F1004F:; CODE XREF: seg007:02F10039
seg007:02F1004F push edi
seg007:02F10050 jmp loc_2F1005C
seg007:02F10050;---------------------------------------------------------------------------seg007:02F10055
db 0E3h, 0E0h, 99h, 5Eh, 3Fh, 0Ch, 55h
seg007:02F1005C;---------------------------------------------------------------------------seg007:02F1005C
seg007:02F1005C
loc_2F1005C:; CODE XREF: seg007:02F10050
seg007:02F1005C pop ebx
seg007:02F1005D pop edx
seg007:02F1005E jmp loc_2F10069
seg007:02F1005E;---------------------------------------------------------------------------seg007:02F10063
db 0E6h, 27h, 0D4h, 7Dh, 72h, 0C3h
seg007:02F10069;---------------------------------------------------------------------------seg007:02F10069
seg007:02F10069
loc_2F10069:; CODE XREF: seg007:02F1005E
;In a stack the address of return after performance of the instruction call loc_2F1004F
seg007:02F10069 add edx, 1F1h
seg007:02F10069 lays;---------------------------------------------------------------------------seg007:02F1006F
db 13h dup (90h)
seg007:02F10082;---------------------------------------------------------------------------seg007:02F10082
mov esi, 2Fh; '/'
seg007:02F10087 mov bl, dh
seg007:02F10089
seg007:02F10089 loc_2F10089:; CODE XREF: seg007:02F1016B j
seg007:02F10089 push dword ptr [edx]
seg007:02F1008B and ebx, 1B9E6815h
seg007:02F10091 pop ecx; In ecx - the ciphered double word
seg007:02F10092 mov ebx, 67DD3A64h
seg007:02F10097 add ecx, 99117BDh; Action 1
seg007:02F1009D sbb bx, 8085h
seg007:02F100A2 push edi
seg007:02F100A3 sub bh, 83h; 'â'
seg007:02F100A6 pop ebx
seg007:02F100A7 add ecx, 2130E1B2h; Action 2
seg007:02F100AD mov ebx, 3EADBF30h
seg007:02F100B2 add ecx, 48408503h; Action 3
seg007:02F100B8 jmp loc_2F100D1
seg007:02F100B8;---------------------------------------------------------------------------seg007:02F100BD
db 5Ch, 65h, 3Ah, 0EBh, 48h, 0E1h, 6, 0C7h, 0F4h, 1Dh
seg007:02F100BD db 92h, 63h, 60h, 19h, 0DEh, 0BFh, 8Ch, 0D5h, 0EAh, 0DBh
seg007:02F100D1;---------------------------------------------------------------------------seg007:02F100D1
seg007:02F100D1
loc_2F100D1:; CODE XREF: seg007:02F100B8 j
seg007:02F100D1 mov ebx, 40853042h
seg007:02F100D6 push ecx
seg007:02F100D7 jmp loc_2F100EF
seg007:02F100D7;---------------------------------------------------------------------------seg007:02F100DC
db 0AFh, 0BCh, 45h, 9Ah, 0CBh, 0A8h, 0C1h, 66h, 0A7h, 54h
seg007:02F100DC db 0FDh, 0F2h, 43h, 0C0h, 0F9h, 3Eh, 9Fh, 0ECh, 0B5h
seg007:02F100EF;---------------------------------------------------------------------------seg007:02F100EF
seg007:02F100EF
loc_2F100EF:; CODE XREF: seg007:02F100D7 j
seg007:02F100EF pop dword ptr [edx]; Record on a place of 4 deciphered bytes
seg007:02F100F1 sbb bx, 1D97h
seg007:02F100F6 sub edx, 2
seg007:02F100F9 pusha
seg007:02F100F9;---------------------------------------------------------------------------seg007:02F100FA
byte_2F100FA db 16h dup (90h)
seg007:02F10110;---------------------------------------------------------------------------seg007:02F10110
mov bh, 31h; '1'
seg007:02F10112 jmp loc_2F1011F
seg007:02F10112;---------------------------------------------------------------------------seg007:02F10117
db 50h, 49h, 4Eh, 6Fh, 7Ch, 5, 5Ah, 8Bh
seg007:02F1011F;---------------------------------------------------------------------------seg007:02F1011F
seg007:02F1011F
loc_2F1011F:; CODE XREF: seg007:02F10112 j
seg007:02F1011F popa
seg007:02F10120 dec edx
seg007:02F10121 dec edx; Reduction of the address on 4 (sub edx, 2; dec edx; dec edx)
seg007:02F10122 js loc_2F1012E
seg007:02F10128
seg007:02F10128 loc_2F10128:
seg007:02F10128 xor ebx, 72129B9h
seg007:02F1012E
seg007:02F1012E loc_2F1012E:; CODE XREF: seg007:02F10122 j
seg007:02F1012E sub esi, 1
seg007:02F10131 jnz loc_2F1014D; esi - the
counter seg007:02F10137
seg007:02F10137 loc_2F10137:
seg007:02F10137 jmp loc_2F10177; Transition to the deciphered code
Such decodings of a code meet very much frequently in the code of a protector. To decipher, very conveniently to use the emulator x86. We put it(him) on the beginning (02F10039), and on 02F10137 address It is possible to put брэйкпоинт and to start the emulator a command(team) run, or to put on this address the cursor and to give a command(team) run to cursor. The code ahead will be deciphered without problems. Now it is possible to look it(him) further. The command(team) to the address 02F101C5 - a call подпроцедуры almost in the beginning of page very interestingly looks. We shall look at this procedure:
seg007:02F10004 pop ebp
seg007:02F10005 call $ +5
seg007:02F1000A pop eax
seg007:02F1000B push eax
seg007:02F1000C sub eax, 0Ah
;We read displacement of the stolen code from the address of return from the given procedure
seg007:02F10011 mov eax, [eax]
seg007:02F10013 add ebp, eax
seg007:02F10015 pop eax
seg007:02F10016 add eax, 16h;
Also we write down the address as argument of a command(team) push to the address 02F10020
seg007:02F1001B mov [eax+1], ebp
seg007:02F1001E popf
seg007:02F1001F popa
seg007:02F10020 push 2F101CAh
seg007:02F10025 retn; Actually transition on краденный a code
Now means so, all procedures of such type are identical, it is possible to pass on a code, to make changes to procedure in the beginning of page. Only so simply here to not bring, the address of transition (argument of a command(team) push) each time is rewritten. But it is possible to take advantage of other circumstance, after the instruction ret we have a correct context of a stream, i.e. all values of registers and a stack same as before occurrence of exception, differently краденный the code would be carried out incorrectly. If to clean(remove) a command(team) push to the address 02F10020 the command(team) retn will transfer management to the address which is in a stack at occurrence of exception. Using these data, simply we change опкод commands(teams) push imm32 on mov eax, imm32. And at processing intercepted ZwContinue we shall add in a stack the address of return which will return us on a cycle touching such protective designs, and after return to register EAX we shall receive краденного address of a code! Here such simple change all is solved, and it is not necessary to decipher and restore anything краденный a code manually. It are necessary to find out his(its) length only. It is simple, since after a code such instructions follow:
seg007:02F10225 push eax
seg007:02F10226 push eax
seg007:02F10227 mov eax, 355C4h;
Displacement is relative ImageBase. Further the address, where
подадает management after working off краденного a
code seg007:02F1022C mov [esp+4], eax
seg007:02F10230 pop eax is formed
Further a code, which зашифровывался earlier зашифровывается back, it for a reuse of a code. And even further it is seen here it:
seg007:02F10388 call near ptr byte_2F10394
seg007:02F10388;---------------------------------------------------------------------------seg007:02F1038D
db 83h, 0, 39h, 7Eh, 0DFh, 2Ch, 0F5h
seg007:02F10394 byte_2F10394 db 1Ah dup (90h); CODE XREF: seg007:02F10388 p
seg007:02F103AE;---------------------------------------------------------------------------seg007:02F103AE
pop esi seg007:02F103AF
call $ +5
seg007:02F103B4 pop ebp
seg007:02F103B5 add ebp, 18h; ebp = 2F103CCh;
Record of unit to the address 2F103CCh - an element of
synchronization seg007:02F103BB mov dword ptr [ebp+0], 1
seg007:02F103C2 mov eax, [ebp+4];
Record in a stack of the address of
return seg007:02F103C5 add [esp+24h], eax
seg007:02F103C9 popf
seg007:02F103CA popa;
Well and actually return
seg007:02F103CB retn
seg007:02F103CB;---------------------------------------------------------------------------seg007:02F103CC
dd 2
seg007:02F103D0 dd 400000h
seg007:02F103D4 db 38h; 8
Problem in that it is necessary to repeat actions of this code (to write down 1 to the address 2F103CCh), differently a cycle обламается for the lack of synchronization. Also in all it присутсвует one strangeness, last such краденный the block is restored incorrectly (00436086 address), is necessary to restore it(him) separately, for example at the following start, and to replace a piece in дампе. Specially for this purpose in a source code the opportunity of record in a log-file of all addresses is stipulated, whence have filched a code. It is necessary to see(overlook) all addresses and if somewhere the code looks incorrectly needs to begin search not all over again the section of a code, and from that address from a file. At unpacking XProtector'á both 1.07, and 1.08 last is incorrectly restored only краденный the block. If at last all blocks are restored correctly, that unpacking is completed.
7. Definition of presence XProtector'á in memories and his(its) elimination
Now with a kind the program functions normally, but it is necessary to start the information(inquiry) as she(it) will take off. The reason for this - not protection of a code, and a straight line call on an adapter around IAT and tables of transitions. Fortunately such only 4, all of them are concentrated in one place. Their addresses - 439B59h, 439BA5h, 439BC7h and 439BD7h. To look, that it for functions, it is enough to remove(take off) дамп where the table of import has been corrected, there they will be directed directly on API functions. It is possible to open in IDA libraries kernel32.dll and advapi32.dll and to look, that it for functions. And it is possible to make it in a debugger. By the way, it is possible to notice, that before everyone call'ом or the ambassador there is an instruction nop, it means, that on this place there was a 6-byte command(team), i.e. call mem32. So, functions the following:
439B59h - GetProcAddress
439BA5h - RegOpenKeyExA
439BC7h - RegQueryValueExA
439BD7h - RegCloseKey
Now finding these functions in a directory of import correct instructions. The information(inquiry) began to open, and in general the program functions completely, only here it is wrong. It is expressed that packed unpacked XProtector'ом programs do not work. This protection against unpacking appears actually hardly probable not the most powerful since it is necessary to test very actively the unpacked program and if the mistake it is necessary реверсить any more a protector and not protection of the program, and its(her) basic code is found. Besides, here the mistake is shown at all in the program, that even more complicates business. Research in this case is too unpleasant, therefore I shall result it(him) in strongly short variant.
The packed program takes off on интсрукции, using the register ebp as displacement. And displacement has not changed. Look at 401A6Eh address in the unpacked program, you увидете code XProtecor'á without scrambled a code, and the main thing with displacement concerning where the code now and lays. I.e. at packing displacement should will change, and they do not vary. At packing XProtector the length of the instruction, и.т.д supports the special table where the address of the instruction is stored(kept). During any moment this table should be processed and filled by correct displacement. The beginning of the table is to the address 45295Eh. With the help xref'ов it is possible to see(overlook) everything, that procedure to the address 42BB7Fh just that is necessary is done(made) with the table, and. There there is a check of an element of the table, calculation of displacement and record of it(him) not a place (in the ready instruction which is located in packed exe). And record looks very interestingly:
CODE ____:0042BC16 loc_42BC16:; CODE XREF: accept_relocations+78
CODE ____:0042BC16 lea esi, ds:4511CEh
CODE ____:0042BC1C sub esi, 0Eh; esi = 4511C0h
;And to this address the address belonging to a stack, very interestingly lays..
CODE ____:0042BC1F mov esi, [esi]
CODE ____:0042BC21 cmp dword ptr [esi+4], 1
;And if there in a stack not unit changes of displacement are not kept!
CODE ____:0042BC25 jnz short loc_42BC2B
CODE ____:0042BC27 mov [ecx+eax+1], ebx
CODE ____:0042BC2B
CODE ____:0042BC2B loc_42BC2B:; CODE XREF: accept_relocations+A6;
Further goes затирание an element of
table CODE ____:0042BC2B mov eax, 0FFFFFFFFh
CODE ____:0042BC30 mov ecx, 5
CODE ____:0042BC35 rep stosd
CODE ____:0042BC37 jmp loc_42BBAF
In as, means XProtector has thrust in a stack unit, has written down in section of the data the address and checks it(him). Check xref'ов on 4511C0h still more some similar situations. Editing of transitions here will not help, therefore we do(make) so: we write to the address 4511C0h value 4511C0h, and on following DWORD'Ò we write down unit. Since following DWORD too differs on time of performance (value 80000002h) that it too is finished after unit for secure. And at last we receive completely the efficient unpacked program, work is finished!
The research certainly retold above is obscure and labour-consuming, therefore I offer other way: to stop the packed program on OEP and to look, than the stack differs. If differences obvious, as in this case it is necessary to look for the address of a stack where distinctions contain on a exe-file. After that it is possible to correct the unpacked file. Also in addition to all this it is possible to tell, that in XProtector 1.08 this opening with the table of displacement in general have cleaned(removed) and ставнение stacks and search of the address on a file where distinctions are found remains the only thing.
8. Analytics (termination(ending))
So, after overcoming protection of all levels, it is possible to tell, that XtremeProtector it is literally in all surpasses other protectors. It is difficult to find such protection where it was so difficult to remove(take off) дамп and to restore section of a code (Starforce it is not counted), to restore import, and especially to find detection of the packer in memory. At XProtector'á very big prospects of development, it is interesting, how the following version of a protector will look? Whether Остануться there though any openings? In fact on search of openings and строися all unpacking. Present, as though it was necessary мучаться with import if it was impossible to find procedure of his(its) creation by simple interception API. Similarly and with restoration of a code. And if there was no such opportunity the basic and the method of research of protection in a forehead was unique. All this can be compared to opportunities of selection of a key in cryptography. It(He) can be picked up перебором all variants or that is better and faster, use by any vulnerability in algorithm. Rescues only what to protect the program, not having left any opportunity for fast breaking it is practically impossible. Authors XtremeProtector'á have tried to make it and it almost was possible to them.
And in summary it would be desirable to tell, that on such protection as XtremeProtector it is not a pity to waste time, in fact it is possible to learn(find out) a lot of new, both about new ways of protection, and about internal device Windows, and it can very much it is useful.
Archive with tools and source codes here
dragon, [email]c_dragon@mail.ru[/email]
14 August, 2004.
The author: dragon <c_dragon@mail.ru>
1. Analytics (beginning)
Protectors as well as can be divided(shared) many other things into three categories on a level of protection of the program - low end, middle end and high end. To low end it is possible to attribute(relate) all simple packers such as UPX, ASPack, and also some protectors. To middle end such things, as ASProtect, Armadillo, Obsidum undoubtedly concern, etc. And among high end, i.e. the most powerful protectors it is known only two - XtremeProtector and StarForce. Them very good antidebugging (especially it concerns XProtector'á, try it(him) to start if in system costs(stands) softice), rather quite good protection of import, concealment of a program code which to not receive so simply as it can be made with copymem II in Armadillo distinguishes, and the most important - use Ring0 of a code which most strongly complicates research.
It is possible to allocate two ways of removal of protectors. The first - research in a forehead from a point of an input(entrance) up to OEP and a spelling automatic распаковщика. The second - manual unpacking with the help of a presence(finding) and use of "rear entrances" in a code of a protector, with the purpose of removal дампа, presence(findings) OEP, receptions of import and. т. д. At unpacking XProtector'á we shall go естесственно in the second way as it in any case is easier and faster.
2. The small description of protection
As the purpose it will be used XtremeProtector 1.07 DEMO which is accessible on an official site of the manufacturer. At the moment of a spelling of clause(article) version 1.08 is accessible already, but she(it) is protected worse, therefore in clause(article) and will be described 1.07.
Before perusal it is recommended to understand a little the protected mode and device Windows NT, in particular in a nucleus. Without it it will be difficult to understand, how protection works. As to tools the basic will be IDA versions not ancient 4.50. Also editor PE of files (PE Tools recommended), ImpRec, the hexadecimal editor (WinHex), and also package MASM32 will be necessary. Also it is necessary to establish the plug-in - emulator x86 for IDA (it is accessible on wasm.ru) and a plug-in for clearing from scrambled a code (is in archive accompanying clause(article)). All right, now it is possible to proceed(pass) directly to the description.
So, protection will consist of two parts, the most packed program and the driver under a name xprotector.sys which lays in the catalogue \System32\Drivers. During the certain moment of work the code of a protector causes function DeviceIoControl with a code 1800h at which processing the driver carries out(spends) some initialization. We look, that it(he) there does(makes):
Defines(Determines) number of processors in system
Finds IDT address for each processor and resolves access to IDT from the user mode at a level of pages
Opens access to the first page with the data where there is a file with IDT addresses
Opens access to all ports of input-output
In most cases IDT there will be certainly one, only in case of the multiprocessing machine or Pentium IV HT tables of interruptions will be more one though it does not affect unpacking in any way. And that the code of a protector gets direct access in ring0 affects and can do(make) that wants. And it(he) wants that, for example that it(him) did not debug and not дампили much. In fact it is valid, to the started program it will not be risen, attempt сдампить from PE Tools leads to to the message on impossibility of reading of memory of process. If to start softice the appendix is closed and if приаттачится to process Ollydbg will be in general перезагрузка. First of all it is necessary to liquidate антидамповую protection and antidebugging, and then already to think, what to do(make) further
3. Removal антидамповой and antidebugging protection
It is obvious, that if memory is accessible to reading from one process and inaccessibl from another are intercepted API functions for work with memory. We start to look a code of function ReadProcessMemory from kernel32.dll. Apparently interceptions it is not observed. Also them it is not observed and in native api functions NtReadVirtualMemory. Further already a nucleus. As management gets on corresponding function in nucleus WinNT is well described in second clause(article) about packers on wasm.ru. The first where it is necessary to look so it in system service table or is shorter sst - the table of addresses of functions ntoskrnl.exe. For this purpose in archive utility R0cmd.exe and the driver lays. With its(her) help it is possible дампить and to load IDT, SST, SST shadow for ntoskrnl.exe and win32k.sys and in general any sites of memory in the field of a nucleus. For definition of interception it is possible to compare two дампа sst - before start XProtector'á and the ambassador. Tables differ, means XProtector контроллирует some functions ntoskrnl. To find out, what it is functions, displacement отличающися elements in дампе is necessary to divide on 4 and to find number in a file of Zw-functions from library ntdll.dll. In result we have the list of the intercepted functions:
NtAllocateVirtualMemory
NtCreateThread
NtQueryVirtualMemory
NtReadVirtualMemory
ZwTerminateProcess
NtWriteVirtualMemory
The maintenance(contents) of these functions to result there is no sense, there at attempt of access from other process to the protected program the error code comes back. Also it is blocked дамп with the help removed треда (CreateRemoteThread). But most surprising it that the ambassador in обработчике ZwTerminateProcess is not restored neither sst nor idt. Probably the protector has climbed somewhere else, it is probable in the scheduler of streams. I give to check up it that who well understands nucleus WinNT. We here are interested with removal антидампа more. It is obvious, that it(him) to remove(take off), there is enough подгрузить on a place the normal table sst by means of same utility R0cmd. And now it is possible to use such utilities, as PE Tools and ImpRec. But here it is impossible while to use a debugger.
R0cmd/viewidt:??? - allows to look IDT in a text kind. Attention the cut down debugging interruptions int1 and int3 (their address began 0FFFFFFFFh) at once draw. All would seem simply, has restored IDT yes debug, but leaves nothing. At attempt to restore IDT the program or is cut down, or IDT comes back to an initial condition. The matter is that the superfluous streams generated by a protector which check IDT. But though the protected program to debug it is impossible, but it is possible to debug other programs. How it is possible? And here is how, by a call int1 or int3 management gets on 0FFFFFFFFh address, memory to this address usually is not present, therefore there is exception Page fault (*PF), обработчик which too is intercepted. Clearly, that in it(him) also there is a processing of any debugging actions of the user. It is necessary to result his(its) code обработчика:
seg000:F8AB8000 pushf
seg000:F8AB8001 pusha
seg000:F8AB8002 call $ +5
seg000:F8AB8007 pop ebp
seg000:F8AB8008 sub ebp, 1E09229h
seg000:F8AB800E inc dword ptr [ebp+1E0925Fh]
seg000:F8AB8014 cmp dword ptr [ebp+1E0925Fh], 63h
Transition will be executed at overflow of the counter therefore
on a place of int1/int3 addresses in IDT will be written down 0FFFFFFFFh, it is
not especially interesting seg000:F8AB801B ja loc_F8AB80B0
seg000:F8AB8021
seg000:F8AB8021 loc_F8AB8021:; CODE XREF: sub_F8AB8000+128
And here that comparison EIP with 0FFFFFFFFh is necessary, means we go on пореходу on F8AB8041
seg000:F8AB8021 mov eax, [esp+28h]
seg000:F8AB8025 cmp eax, 0FFFFFFFFh
seg000:F8AB8028 jz short loc_F8AB8041
--------------------------------------------------------------------------------
seg000:F8AB8041 loc_F8AB8041:; CODE XREF: sub_F8AB8000+28
seg000:F8AB8041 mov eax, 1
seg000:F8AB8046 mov ecx, eax
seg000:F8AB8048 or eax, eax
Well is not present, that it is simple jmp to write..
seg000:F8AB804A jnz loc_F8AB8138
--------------------------------------------------------------------------------
seg000:F8AB8138 push fs
seg000:F8AB813A mov eax, 30h; the selector for the register fs in a nucleus - 30h
seg000:F8AB813F db 66h
seg000:F8AB813F mov fs, ax
;We receive the index on structure KTHREAD (or ETHREAD)
seg000:F8AB8142 mov eax, large fs:KPRCB.CurrentThread
;And it is the index on KPROCESS, it(he) the index on object of
process seg000:F8AB8148 mov eax, [eax+KTHREAD.ApcState. Process]
seg000:F8AB814B pop fs
seg000:F8AB814D mov ebx, eax
seg000:F8AB814F and ebx, 7FFFFFFFh
;Probably to this address or hardly the index on object
protected XProtector'ом process, if it(he) current, or a constant 47616420h if is not present further enters
the name.
All this probably occurs in a code of switching of
streams seg000:F8AB8155 mov esi, 0F8AB6000h
seg000:F8AB815A cmp dword ptr [esi], 0
seg000:F8AB815D jz loc_F8AB8075
seg000:F8AB8163
seg000:F8AB8163 loc_F8AB8163:; CODE XREF: sub_F8AB8000+17A
seg000:F8AB8163 add esi, 4
seg000:F8AB8166 cmp dword ptr [esi], 47616420h
Ага, transition to a call old обработчика interruptions if process is not protected.
seg000:F8AB816C jz short loc_F8AB8187
seg000:F8AB816E cmp [esi], eax
And further transitions not there where it is necessary, and they are carried out, if
*PF has taken place in the protected process
seg000:F8AB8170 jz short loc_F8AB817C
seg000:F8AB8172 cmp [esi], ebx
seg000:F8AB8174 jz loc_F8AB8075
seg000:F8AB817A jmp short loc_F8AB8163
It is obvious, that if пропатчить transition to the address F8AB816C (In general that it(he) can be and another, the main thing, that this address is calculated as *PF+16Ch. In the programs protected XProtector'ом 1.08 displacement will be 17A). Патчить the nucleus without special tools is impossible, but possible to take advantage again R0cmd. For this purpose it is necessary to create a file in the size of 1 byte and to write down in him(it) EB, and then to load, using a command(team)/load. After restoration sst and a patch обработчика *PF debugging with help Ring3 of debuggers, for example Ollydbg becomes possible(probable). On softice to expect it is not necessary, too a lot of attention was given it(him) by developers.
4. Restoration of import and presence(finding) OEP
Now we start traditional enough things in unpacking - to import and OEP. For presence(finding) OEP it will be described the whole two ways, but for one of them it is required распалогать by some information, namely the address of procedure of decoding of blocks of a code which to learn(find out) it is not obviously possible yet. Therefore for the beginning a way such: we find the table with adapters on imported functions, and instead of the present(true) transitions to write down there transitions to function which shall tell shows in MessageBox'Ñ the address of the call. It is obvious, that this address will be is close to OEP. It are necessary to find only the table of these transitions and пропатчить her(it). To find the table, problems do not arise, simply it is necessary to look through a code for calls of procedures and to look, where it(he) conducts. It is visible, that the table of transitions begins to the address 439850h and comes to an end on 439AF0h address And here so that пропатчить, problems is greater. Way such, we create process with the frozen stream (flag CREATE_SUSPENDED in соотв. Parameter), then using API CreateRemoteThread with the address of the removed stream equal to the address of function LoadLibraryA and the parameter equal to a name introduced DLL it is loaded this the most introduced DLL in address space of the protected program. The name естесственно should be registered beforehand with the help of pair functions VirtualAllocEx and WriteProcessMemory. All this is shown in a source code. Now DLL will receive notices on loading in address space of process, creation of a stream, и.т.д. The most such obvious way - to use a multithreading of a code of a protector, i.e. to wait creations of last stream, and during processing the notice to alter all this table of transitions under the needs, but XProtector not so it is simple, it(he) of it does not allow (If in the table changes the protector will change transitions once again, one change to it(him) will be appreciable appears a little). The output(exit) in that all this to do right after fillings of this table, and is even better during its(her) creation. Now this code is necessary for finding somehow. It very much is useful and at restoration of import since other opportunities well in any way do not approach. Reduction of a code of adapters the order and serial comparison with exported functions - is too difficult, and the variant to palm off instead of functions push XXXXXXXX/ret does not pass adapters of a kind, the protector notices it and is cut down.
If присмотрется to addresses of adapters it is possible to notice, that they are in the allocated virtual memory with which it is possible to allocate with function VirtualAlloc. Now is farther, depending on version Windows the size of code API of functions different, allocation of memory means occurs directly in procedure of creation of import. The output(exit) means in catching calls of this API. Basically at a protector all is seized, patch API is direct kernel32.dll will not help, since she(it) is read directly from a disk in memory, processed, and functions therefrom are caused. In a nucleus to climb too uneasily, the idealest place for interception - Zw-functions means. Function ZwAllocateVirtualMemory necessary to us (I Hope in Microsoft will not take offence, in fact it is forbidden to spread source codes Windows) here is how looks:
.text:77F75832 public ZwAllocateVirtualMemory
.text:77F75832 ZwAllocateVirtualMemory proc near
.text:77F75832 mov eax, 11h
.text:77F75837 mov edx, 7FFE0300h
.text:77F7583C call edx
.text:77F7583E retn 18h
.text:77F7583E ZwAllocateVirtualMemory endp
Simply we change the instruction to the address 77F75837 so that in the register edx обработчика address of the intercepted procedure which, say, collects all addresses calls VirtualAlloc in a file was. To receive the address of call VirtualAlloc it is possible, having read it(him) from a stack. Displacement is relative esp can be found out, having debugged the program causing VirtualAlloc. In Windows XP SP1 this displacement is equal 68h. At unloading DLL contents of this file can be thrown off in a file, as well as it is made in a source code on restoration of import.
The address which should draw attention - 7E0B0Eh since at return on this address memory which addresses very much remind addresses of adapters is allocated. From him(it) also it is necessary to dig all procedure. Here I shall result only the most interesting moments in this procedure. Here for example a small piece of a code which keeps displacement after опкода 0E9 (long jmp):
XPROT ___:007E0C21 lStoreJumpToImportFunction:; CODE XREF: XPROT ___:007E0C05
XPROT ___:007E0C21; XPROT ___:007E0C10
;edi - the address on which there is this displacement
XPROT ___:007E0C21 mov eax, [ebp+AddressOfImportFunction]
XPROT ___:007E0C27 sub eax, edi
XPROT ___:007E0C29 sub eax, 4
XPROT ___:007E0C2C stosd
For the beginning it will suffice us, we change the instruction mov eax, [ebp+AddressOfImportFunction] for something like mov eax, offset import_accepted. To change it is necessary after first interception ZwAllocateVirtualMemory with the required address of return from VirtualAlloc. And again we are waited with a surprise, namely one bad MessageBox with the message " An Error has ocurred while loading imports ". Certainly no mistake can be, and here check of integrity of a code of procedure very much even can. Looking through a code of creation of procedure is farther, I was involved with the following code:
XPROT ___:007E0737 pusha
XPROT ___:007E0738 lea esi, [ebp+BeginProtectedArea]; 007E046F - the beginning of
procedure XPROT ___:007E073E lea edi, [ebp+EndProtectedArea]; 007E12F9 - and the end of
procedure XPROT ___:007E0744 sub edi, esi
XPROT ___:007E0746 mov edx, edi; edx - length of checked code
XPROT ___:007E0748 mov edi, [ebp+1D70619h]
XPROT ___:007E074E or ecx, 0FFFFFFFFh
XPROT ___:007E0751
XPROT ___:007E0751 hash_loop:; CODE XREF: XPROT ___:007E0761
XPROT ___:007E0751 xor eax, eax
XPROT ___:007E0753 mov al, [esi]
XPROT ___:007E0755 xor al, cl
XPROT ___:007E0757 inc esi
XPROT ___:007E0758 mov eax, [edi+eax*4]
XPROT ___:007E075B shr ecx, 8
XPROT ___:007E075E xor ecx, eax
XPROT ___:007E0760 dec edx
XPROT ___:007E0761 jnz hash_loop
XPROT ___:007E0767 mov eax, ecx
XPROT ___:007E0769 not eax
XPROT ___:007E076B cmp [ebp+ValidHashValue], eax; Here and comparison..
XPROT ___:007E0771 jz loc_7E0781; well here conditional transition.
XPROT ___:007E0777 mov dword ptr [ebp+1D71831h], 1
XPROT ___:007E0781
XPROT ___:007E0781 loc_7E0781:; CODE XREF: XPROT ___:007E0771
XPROT ___:007E0781 popa
Made unconditional transition to the address 007E0771h will resolve any updatings in procedure of creation of import, that very much even it is good. For example it allows a program - example to display rather humiliating окошко with an inscription " dump me!!! " And heading OEP near 42A37Ah. And it is valid OEP lays absolutely beside, to the address 42A373h. But the address on which it is transferred managements after working off of a code of a protector is little bit above, it is connected to protection of a code about(near) OEP, details will be considered below when it will be told about protection of a code.
Now we shall engage in reception of addresses of imported functions that it was possible using imprec, to restore a directory of import. Since functions kernel32, user32 and advapi32 there should be a group of comparisons and transitions which should be found and corrected are protected only. I think for этогол such group will leave:
XPROT ___:007E08A9 loc_7E08A9:; CODE XREF: XPROT ___:007E0828 j;
As on a palm four transitions which editing will lead to to the pure(clean) table lay;
import and the table of transitions (is more true almost pure(clean), one function nevertheless придёться to distinguish
manually;
in this case this function - GetStartupInfoA
XPROT ___:007E08A9 cmp dword ptr [ebp+1D70A05h], 1
XPROT ___:007E08B0 jz lScrambled0
XPROT ___:007E08B6 cmp ecx, [ebp+BaseOfKernel32]
XPROT ___:007E08BC jz lScrambled0
XPROT ___:007E08C2 cmp ecx, [ebp+BaseOfUser32]
XPROT ___:007E08C8 jz lScrambled0
XPROT ___:007E08CE cmp ecx, [ebp+BaseOfAdvapi32]
XPROT ___:007E08D4 jz lScrambled0
XPROT ___:007E08DA
XPROT ___:007E08DA lNoScrambled:; CODE XREF: XPROT ___:007E08FD
XPROT ___:007E08DA; XPROT ___:007E0922...
XPROT ___:007E08DA lea ebx, [ebp+GetProcAddressX0]
XPROT ___:007E08E0 call ebx
XPROT ___:007E08E2 mov edi, eax;
Here all is simple, the correct address of function enters the name and is transferred somewhere;
Further - on creation of transition and element IAT. Management should get here
XPROT ___:007E08E4 mov [ebp+AddressOfImportFunction], eax
XPROT ___:007E08EA jmp loc_7E0B4A
Having replaced each transition by six instructions nop we achieve creation of the pure(clean) table of import and transitions. To find IAT here it is not difficult, it is necessary to look only field Base Of Data in PE heading, usually the table of import there and lays. Now at last it is possible to restore import, but неободимо also to reorient transitions in the table that they specified elements IAT instead of in emptiness. For this purpose in archive the small utility also lays. After all it it is possible to tell, that the first stage of unpacking is completed, but XtremeProtector also has taken care of protection of the code. It is necessary to work further receiving all code in an open kind.
5. Protection of a code of a protector, scrambled a code
As there will be an active research of a code of a protector it is necessary to tell a little that prevents his(its) research longer. First of all it is a scrambled-code, i.e. a code which is strongly diluted with dust. I bring some kinds of dust below:
--------------------------------------------------------------------------------
push eXX
push eXX...
sidt
[esp - 2]; Kept IDT address is
not used...
pop eXX...
pop
eXX
--------------------------------------------------------------------------------
push eax
push edx...
rdtsc;
Reading of the counter of steps of the processor, also is
not used...
pop edx...
pop
eax
--------------------------------------------------------------------------------
pusha...
popa
--------------------------------------------------------------------------------
Also there are senseless conditional and unconditional transitions, instructions of a kind mov eax, eax. Except for a scrambled-code also there are designs of the following kind:
--------------------------------------------------------------------------------
push eXX
call proc0
db 0XXh; Garbage byte
jmp [esp - 0Ch]
proc0:
pop eXX
mov [esp-8], eXX;
displacement concerning "garbage" байта Here increases,
management
add [esp-8], 20h
inc eXX there is then transferred; Detour garbage байта
push eXX
retn
--------------------------------------------------------------------------------
Try потрассировать on F8 such code in Softice and will see something strange, instructions jmp [esp-0Ch] are farther to pass will fail, who it can can explain?
Is present as well such code (deciphering ahead a double word):
push ebx
push edx
push edx; Registers естесственно can be and others
sidt [esp - 2]
;Usually in ebx it turns out 0Ch or 1Ch, that corresponds(meets) to displacement of parameters int1 or int3 in IDT
mov ebx, XXXXXXXX
xor ebx, XXXXXXXX; Instead of xor there can be other arithmetic instruction
pop edx
add edx, ebx
;The key is written directly in IDT, all the same debugging interruptions are
cut down mov dword ptr [edx], XXXXXXXX
mov edx, [edx]
call $ +5
pop ebx
add ebx, XX
xor [ebx], edx; Decoding of a part of a code ahead...
xor
[ebx], edx; Here restoration for an opportunity of repeated execution(performance) of
a code push 0FFFFFFFFh
;There обработчиков int1 addresses and int3 become equal to the transmitted parameter
call proc0
pop edx
pop ebx
This code also is diluted with a significant amount of garbage instructions.
Also it is necessary to mention two kinds ring0-дишифровщиков a code. They are too complex(difficult), therefore their code I shall not result. The plug-in for IDA in archive allows to replace the most widespread scrambled-code with group nop'ов, and supports one of ring0-дешифровщиков. It(he) strongly facilitates research, in fact scrambled the code meets in the procedures responsible for decoding of a code, the driver xprotector.sys, and it is a lot of where still.
6. Full restoration of a code of the program
Received in the previous steps дамп it is not started at all, a mistake, which reason - too much an absent code which now and we shall restore at once gives out. The first, than costs(stands) занятся, so it подгрузить отсутсвующий a code which sites are obviously visible in PE Tools in an option dump region. Something similar on CopyMem II in Armadillo, but only with that difference, that process one, and exceptions processes a code of a protector. One more difference from CopyMem II - sites of a code are deciphered at attempt of performance, instead of at attempt of any access to memory. The way of decoding is easy enough, we transfer management to such site of memory, and the protector after processing exception should cause in any case function ZwContinue for продолженя performance. The first and unique parameter at it(her) - the index on structure CONTEXT. That management was not transferred further, it is necessary to intercept simply her(it) in the same way, as ZwAllocateVirtualMemory at creation of import and to reorient EIP for the subsequent execution(performance) of a cycle. The received pieces of a code (all in the size 2000h, i.e. two pages) to put(fold) in the allocated(removed) area of memory, and after the termination(ending) of a cycle simply to resolve access to memory and to copy them on a place. Such way also is used in a source code. All this to make it is necessary, because XProtector at opening one pair pages, can close another.
There are also three more designs for protection of a code, shall consider all over again designs, and then ways of reception of a code.
call XXXXXXXX; the Address of procedure of decoding, in this case - 7DC1BBh
dd 0XXh; the Identifier of a stream which all this will
decipher dd 0; 0 - decoding, 1 - an
encryption dd 0XXh; length of
a code db 06Fh; garbage byte...-;
Further the ciphered code.
The finishing part can will be distinguished. If the ciphered code is carried out only once, it(he) затирается by zero:
pusha
call $ +5
pop edi
sub edi, 0XXh
mov ecx, 0XXh; Here and above 0XXh - length of the ciphered code increased on 1
xor eax, eax
rep stosb
popa
And here if the code is executed repeatedly from such затирания anything good will not leave, therefore end of a code such:
call XXXXXXXX; the Address of procedure of enciphering of a code - another, here it(he) is equal 007C0D1Bh
dd 0XXh
dd 1
dd 0XXh
db 06Fh
The principle of action of these procedures consists in filling variables with the data on the address, length, и.т.д. Then procedure causes function SetEvent and is started up in an infinite cycle jmp eax. The deciphering stream fulfils and transfers management to the deciphered code by means of an adapter. Теоритически besides to change EIP in the other stream call SetThreadContext is necessary. All again solves interception native api, this time ZwSetContextThread. It is enough to change EIP for the adapter and to continue a cycle of restoration of a code since it(he) remains in an open kind. Designs such should be found direct search, better and to not think up. Also it is necessary to provide cleaning of a code from calls and parameters of encryption / decoding of a code and replacement in his(its) zero. Now we pass further.
By consideration of procedure of creation of import it was possible to notice, that instead of function wsprintfA its(her) real address, and at all(even not) a scrambled-adapter, and any suspicious code is put not. And in the code of the program there are not less suspicious calls wsprintfA strange parameters. Work of this function it is possible to observe under a debugger, or, that it is easier, under the emulator x86 in IDA. To result here details there is no sense since to decipher the sites of a code opened by this function simply elementary - transfer(pass) management on such call and change the address of return. These calls also are necessary for cleaning, as an opening call:
push 78263845h;
All XX - parameters of
decoding push XX
push 0; 0 - an opening call, decoding of
a code push XXXXXXXX
push XXXXXXXX;
78263845h is a constant ('x*8E' or 'E8*x'), on it(her);
обработчик wsprintfA learns(finds out), that it is necessary to do(make) - to pass on real wsprintfA;
or to decipher a
code push 78263845h
call XXXXXXXX; обработчика wsprintfA Address (the address of transition jmp on him(it) is more exact)
And closing:
push 78263845h
push XX
push 1; 1 - a closing call, enciphering of
a code push XXXXXXXX
push XXXXXXXX
push 78263845h
call XXXXXXXX
And at last last most complex(difficult) stage - restoration of a stolen code, and it(him) steal not on OEP, and on all section of a code. It is done(made) such with the help sdk XProtectora for protection of any important sites of a code, we shall tell checks of the entered password.
All these protection of a code are found out at attempt of start of the unpacked program with cut off section XPROT. Here for example we shall try to open a file for protection, the program will take off on 435569h address on wrong опкоде. Here general structure of such protection of a code:
jmp invalid_opcode
db "xpro" It simply the
signature dd 00 - the beginning, 1 - the termination(ending).
dd 0
db "xpro"
invalid_opcode:...
Anyone опкод, causing the sixth exception (invalid opcode)
At the end of this site there is the same, only with unit instead of zero. For reception of a code придёться to look, where management after processing exception gets. It appears, that EIP varies, and management is transferred somewhere far in virtual memory. We shall look, that there such. The beginning does not represent anything interesting, expectation of occurrence of the two to the address 2F103CCh is simple. Decoding laying ahead of a code (the code resulted below is processed by a plug-in from archive) further begins:
seg007:02F10039 call loc_2F1004F; the Beginning of
decoding seg007:02F10039;---------------------------------------------------------------------------seg007:02F1003E
db 75h, 0Ah, 7Bh, 98h, 0F1h, 0D6h, 57h, 44h, 2Dh, 62h
seg007:02F1003E db 0F3h, 0B0h, 29h, 0AEh, 4Fh, 0DCh, 0E5h
seg007:02F1004F;---------------------------------------------------------------------------seg007:02F1004F
seg007:02F1004F
loc_2F1004F:; CODE XREF: seg007:02F10039
seg007:02F1004F push edi
seg007:02F10050 jmp loc_2F1005C
seg007:02F10050;---------------------------------------------------------------------------seg007:02F10055
db 0E3h, 0E0h, 99h, 5Eh, 3Fh, 0Ch, 55h
seg007:02F1005C;---------------------------------------------------------------------------seg007:02F1005C
seg007:02F1005C
loc_2F1005C:; CODE XREF: seg007:02F10050
seg007:02F1005C pop ebx
seg007:02F1005D pop edx
seg007:02F1005E jmp loc_2F10069
seg007:02F1005E;---------------------------------------------------------------------------seg007:02F10063
db 0E6h, 27h, 0D4h, 7Dh, 72h, 0C3h
seg007:02F10069;---------------------------------------------------------------------------seg007:02F10069
seg007:02F10069
loc_2F10069:; CODE XREF: seg007:02F1005E
;In a stack the address of return after performance of the instruction call loc_2F1004F
seg007:02F10069 add edx, 1F1h
seg007:02F10069 lays;---------------------------------------------------------------------------seg007:02F1006F
db 13h dup (90h)
seg007:02F10082;---------------------------------------------------------------------------seg007:02F10082
mov esi, 2Fh; '/'
seg007:02F10087 mov bl, dh
seg007:02F10089
seg007:02F10089 loc_2F10089:; CODE XREF: seg007:02F1016B j
seg007:02F10089 push dword ptr [edx]
seg007:02F1008B and ebx, 1B9E6815h
seg007:02F10091 pop ecx; In ecx - the ciphered double word
seg007:02F10092 mov ebx, 67DD3A64h
seg007:02F10097 add ecx, 99117BDh; Action 1
seg007:02F1009D sbb bx, 8085h
seg007:02F100A2 push edi
seg007:02F100A3 sub bh, 83h; 'â'
seg007:02F100A6 pop ebx
seg007:02F100A7 add ecx, 2130E1B2h; Action 2
seg007:02F100AD mov ebx, 3EADBF30h
seg007:02F100B2 add ecx, 48408503h; Action 3
seg007:02F100B8 jmp loc_2F100D1
seg007:02F100B8;---------------------------------------------------------------------------seg007:02F100BD
db 5Ch, 65h, 3Ah, 0EBh, 48h, 0E1h, 6, 0C7h, 0F4h, 1Dh
seg007:02F100BD db 92h, 63h, 60h, 19h, 0DEh, 0BFh, 8Ch, 0D5h, 0EAh, 0DBh
seg007:02F100D1;---------------------------------------------------------------------------seg007:02F100D1
seg007:02F100D1
loc_2F100D1:; CODE XREF: seg007:02F100B8 j
seg007:02F100D1 mov ebx, 40853042h
seg007:02F100D6 push ecx
seg007:02F100D7 jmp loc_2F100EF
seg007:02F100D7;---------------------------------------------------------------------------seg007:02F100DC
db 0AFh, 0BCh, 45h, 9Ah, 0CBh, 0A8h, 0C1h, 66h, 0A7h, 54h
seg007:02F100DC db 0FDh, 0F2h, 43h, 0C0h, 0F9h, 3Eh, 9Fh, 0ECh, 0B5h
seg007:02F100EF;---------------------------------------------------------------------------seg007:02F100EF
seg007:02F100EF
loc_2F100EF:; CODE XREF: seg007:02F100D7 j
seg007:02F100EF pop dword ptr [edx]; Record on a place of 4 deciphered bytes
seg007:02F100F1 sbb bx, 1D97h
seg007:02F100F6 sub edx, 2
seg007:02F100F9 pusha
seg007:02F100F9;---------------------------------------------------------------------------seg007:02F100FA
byte_2F100FA db 16h dup (90h)
seg007:02F10110;---------------------------------------------------------------------------seg007:02F10110
mov bh, 31h; '1'
seg007:02F10112 jmp loc_2F1011F
seg007:02F10112;---------------------------------------------------------------------------seg007:02F10117
db 50h, 49h, 4Eh, 6Fh, 7Ch, 5, 5Ah, 8Bh
seg007:02F1011F;---------------------------------------------------------------------------seg007:02F1011F
seg007:02F1011F
loc_2F1011F:; CODE XREF: seg007:02F10112 j
seg007:02F1011F popa
seg007:02F10120 dec edx
seg007:02F10121 dec edx; Reduction of the address on 4 (sub edx, 2; dec edx; dec edx)
seg007:02F10122 js loc_2F1012E
seg007:02F10128
seg007:02F10128 loc_2F10128:
seg007:02F10128 xor ebx, 72129B9h
seg007:02F1012E
seg007:02F1012E loc_2F1012E:; CODE XREF: seg007:02F10122 j
seg007:02F1012E sub esi, 1
seg007:02F10131 jnz loc_2F1014D; esi - the
counter seg007:02F10137
seg007:02F10137 loc_2F10137:
seg007:02F10137 jmp loc_2F10177; Transition to the deciphered code
Such decodings of a code meet very much frequently in the code of a protector. To decipher, very conveniently to use the emulator x86. We put it(him) on the beginning (02F10039), and on 02F10137 address It is possible to put брэйкпоинт and to start the emulator a command(team) run, or to put on this address the cursor and to give a command(team) run to cursor. The code ahead will be deciphered without problems. Now it is possible to look it(him) further. The command(team) to the address 02F101C5 - a call подпроцедуры almost in the beginning of page very interestingly looks. We shall look at this procedure:
seg007:02F10004 pop ebp
seg007:02F10005 call $ +5
seg007:02F1000A pop eax
seg007:02F1000B push eax
seg007:02F1000C sub eax, 0Ah
;We read displacement of the stolen code from the address of return from the given procedure
seg007:02F10011 mov eax, [eax]
seg007:02F10013 add ebp, eax
seg007:02F10015 pop eax
seg007:02F10016 add eax, 16h;
Also we write down the address as argument of a command(team) push to the address 02F10020
seg007:02F1001B mov [eax+1], ebp
seg007:02F1001E popf
seg007:02F1001F popa
seg007:02F10020 push 2F101CAh
seg007:02F10025 retn; Actually transition on краденный a code
Now means so, all procedures of such type are identical, it is possible to pass on a code, to make changes to procedure in the beginning of page. Only so simply here to not bring, the address of transition (argument of a command(team) push) each time is rewritten. But it is possible to take advantage of other circumstance, after the instruction ret we have a correct context of a stream, i.e. all values of registers and a stack same as before occurrence of exception, differently краденный the code would be carried out incorrectly. If to clean(remove) a command(team) push to the address 02F10020 the command(team) retn will transfer management to the address which is in a stack at occurrence of exception. Using these data, simply we change опкод commands(teams) push imm32 on mov eax, imm32. And at processing intercepted ZwContinue we shall add in a stack the address of return which will return us on a cycle touching such protective designs, and after return to register EAX we shall receive краденного address of a code! Here such simple change all is solved, and it is not necessary to decipher and restore anything краденный a code manually. It are necessary to find out his(its) length only. It is simple, since after a code such instructions follow:
seg007:02F10225 push eax
seg007:02F10226 push eax
seg007:02F10227 mov eax, 355C4h;
Displacement is relative ImageBase. Further the address, where
подадает management after working off краденного a
code seg007:02F1022C mov [esp+4], eax
seg007:02F10230 pop eax is formed
Further a code, which зашифровывался earlier зашифровывается back, it for a reuse of a code. And even further it is seen here it:
seg007:02F10388 call near ptr byte_2F10394
seg007:02F10388;---------------------------------------------------------------------------seg007:02F1038D
db 83h, 0, 39h, 7Eh, 0DFh, 2Ch, 0F5h
seg007:02F10394 byte_2F10394 db 1Ah dup (90h); CODE XREF: seg007:02F10388 p
seg007:02F103AE;---------------------------------------------------------------------------seg007:02F103AE
pop esi seg007:02F103AF
call $ +5
seg007:02F103B4 pop ebp
seg007:02F103B5 add ebp, 18h; ebp = 2F103CCh;
Record of unit to the address 2F103CCh - an element of
synchronization seg007:02F103BB mov dword ptr [ebp+0], 1
seg007:02F103C2 mov eax, [ebp+4];
Record in a stack of the address of
return seg007:02F103C5 add [esp+24h], eax
seg007:02F103C9 popf
seg007:02F103CA popa;
Well and actually return
seg007:02F103CB retn
seg007:02F103CB;---------------------------------------------------------------------------seg007:02F103CC
dd 2
seg007:02F103D0 dd 400000h
seg007:02F103D4 db 38h; 8
Problem in that it is necessary to repeat actions of this code (to write down 1 to the address 2F103CCh), differently a cycle обламается for the lack of synchronization. Also in all it присутсвует one strangeness, last such краденный the block is restored incorrectly (00436086 address), is necessary to restore it(him) separately, for example at the following start, and to replace a piece in дампе. Specially for this purpose in a source code the opportunity of record in a log-file of all addresses is stipulated, whence have filched a code. It is necessary to see(overlook) all addresses and if somewhere the code looks incorrectly needs to begin search not all over again the section of a code, and from that address from a file. At unpacking XProtector'á both 1.07, and 1.08 last is incorrectly restored only краденный the block. If at last all blocks are restored correctly, that unpacking is completed.
7. Definition of presence XProtector'á in memories and his(its) elimination
Now with a kind the program functions normally, but it is necessary to start the information(inquiry) as she(it) will take off. The reason for this - not protection of a code, and a straight line call on an adapter around IAT and tables of transitions. Fortunately such only 4, all of them are concentrated in one place. Their addresses - 439B59h, 439BA5h, 439BC7h and 439BD7h. To look, that it for functions, it is enough to remove(take off) дамп where the table of import has been corrected, there they will be directed directly on API functions. It is possible to open in IDA libraries kernel32.dll and advapi32.dll and to look, that it for functions. And it is possible to make it in a debugger. By the way, it is possible to notice, that before everyone call'ом or the ambassador there is an instruction nop, it means, that on this place there was a 6-byte command(team), i.e. call mem32. So, functions the following:
439B59h - GetProcAddress
439BA5h - RegOpenKeyExA
439BC7h - RegQueryValueExA
439BD7h - RegCloseKey
Now finding these functions in a directory of import correct instructions. The information(inquiry) began to open, and in general the program functions completely, only here it is wrong. It is expressed that packed unpacked XProtector'ом programs do not work. This protection against unpacking appears actually hardly probable not the most powerful since it is necessary to test very actively the unpacked program and if the mistake it is necessary реверсить any more a protector and not protection of the program, and its(her) basic code is found. Besides, here the mistake is shown at all in the program, that even more complicates business. Research in this case is too unpleasant, therefore I shall result it(him) in strongly short variant.
The packed program takes off on интсрукции, using the register ebp as displacement. And displacement has not changed. Look at 401A6Eh address in the unpacked program, you увидете code XProtecor'á without scrambled a code, and the main thing with displacement concerning where the code now and lays. I.e. at packing displacement should will change, and they do not vary. At packing XProtector the length of the instruction, и.т.д supports the special table where the address of the instruction is stored(kept). During any moment this table should be processed and filled by correct displacement. The beginning of the table is to the address 45295Eh. With the help xref'ов it is possible to see(overlook) everything, that procedure to the address 42BB7Fh just that is necessary is done(made) with the table, and. There there is a check of an element of the table, calculation of displacement and record of it(him) not a place (in the ready instruction which is located in packed exe). And record looks very interestingly:
CODE ____:0042BC16 loc_42BC16:; CODE XREF: accept_relocations+78
CODE ____:0042BC16 lea esi, ds:4511CEh
CODE ____:0042BC1C sub esi, 0Eh; esi = 4511C0h
;And to this address the address belonging to a stack, very interestingly lays..
CODE ____:0042BC1F mov esi, [esi]
CODE ____:0042BC21 cmp dword ptr [esi+4], 1
;And if there in a stack not unit changes of displacement are not kept!
CODE ____:0042BC25 jnz short loc_42BC2B
CODE ____:0042BC27 mov [ecx+eax+1], ebx
CODE ____:0042BC2B
CODE ____:0042BC2B loc_42BC2B:; CODE XREF: accept_relocations+A6;
Further goes затирание an element of
table CODE ____:0042BC2B mov eax, 0FFFFFFFFh
CODE ____:0042BC30 mov ecx, 5
CODE ____:0042BC35 rep stosd
CODE ____:0042BC37 jmp loc_42BBAF
In as, means XProtector has thrust in a stack unit, has written down in section of the data the address and checks it(him). Check xref'ов on 4511C0h still more some similar situations. Editing of transitions here will not help, therefore we do(make) so: we write to the address 4511C0h value 4511C0h, and on following DWORD'Ò we write down unit. Since following DWORD too differs on time of performance (value 80000002h) that it too is finished after unit for secure. And at last we receive completely the efficient unpacked program, work is finished!
The research certainly retold above is obscure and labour-consuming, therefore I offer other way: to stop the packed program on OEP and to look, than the stack differs. If differences obvious, as in this case it is necessary to look for the address of a stack where distinctions contain on a exe-file. After that it is possible to correct the unpacked file. Also in addition to all this it is possible to tell, that in XProtector 1.08 this opening with the table of displacement in general have cleaned(removed) and ставнение stacks and search of the address on a file where distinctions are found remains the only thing.
8. Analytics (termination(ending))
So, after overcoming protection of all levels, it is possible to tell, that XtremeProtector it is literally in all surpasses other protectors. It is difficult to find such protection where it was so difficult to remove(take off) дамп and to restore section of a code (Starforce it is not counted), to restore import, and especially to find detection of the packer in memory. At XProtector'á very big prospects of development, it is interesting, how the following version of a protector will look? Whether Остануться there though any openings? In fact on search of openings and строися all unpacking. Present, as though it was necessary мучаться with import if it was impossible to find procedure of his(its) creation by simple interception API. Similarly and with restoration of a code. And if there was no such opportunity the basic and the method of research of protection in a forehead was unique. All this can be compared to opportunities of selection of a key in cryptography. It(He) can be picked up перебором all variants or that is better and faster, use by any vulnerability in algorithm. Rescues only what to protect the program, not having left any opportunity for fast breaking it is practically impossible. Authors XtremeProtector'á have tried to make it and it almost was possible to them.
And in summary it would be desirable to tell, that on such protection as XtremeProtector it is not a pity to waste time, in fact it is possible to learn(find out) a lot of new, both about new ways of protection, and about internal device Windows, and it can very much it is useful.
Archive with tools and source codes here
dragon, [email]c_dragon@mail.ru[/email]
14 August, 2004.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
看原图
赞赏
雪币:
留言: