首页
社区
课程
招聘
Arm4.xx CopyMeM2 and Debug Blocker
发表于: 2005-5-2 15:16 7559

Arm4.xx CopyMeM2 and Debug Blocker

2005-5-2 15:16
7559
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
KaGra proudly presents:Armadillo 4.xx Public Build CopyMeM2 and Debug Blocker Unpacking
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR

Well,this tutorial would have not been written if there wasn't for the tutorials of
Richardo.After some dayz of transslation,they revealed in frot of my eyes these so
called protections of Armadillo.So,a big thankz for those tutor he wrote.

I used Armadillo 4.05 Bublic Build to protect an exe.The protection options I used
are CopyMeM2+Debug Blocker and Memory patching protections.This featurez also contain
Import table elimination,but in this tutorial I will create a valid Dump,without
rebuilding IAT.This last one will be done in the second part of that tutorial,in a
seperate txt,later.

In zip I have the Dump (not IAT fixed),the protected and a clear one (not packed).
I also have the clear,cause the only thing that clear defers from the Dump (not IAT fixed)
is the IAT table.So,if u load the clear in Olly and copy-paste section 405000 to the same
section of the Dumped,the dumped will run just fine under Olly.At the end of that tutorial
you will be able to create this dump,and then only thing left is IAt rebuilding.

Tools used:Olly v1.10,LordPE,OllyDump plug and HideOlly plug.I also patched Olly
against the OutputDebugStringA exploit.

I will not make much talking about the anti-debugging tricks,since you have patched
Olly and you have Hide Olly plugins.

Now,what is that so called CopyMEM protection and what does debugger blocking mean?

Whan an Armadillo protected Application starts executing,it creates also another
process.This process is called child,and the first executed exe is called father.
So,when you will run it under Olly and check in process list,you will find two
processes with the same name,with different ID's.The red one in process list is
the current proccess Olly debugs,and is the father,and the black one is the child.

So,debugger blocking is actually the incapabillity of Olly as a Ring-3 debugger to
debugg the child,which is the "REAL" actuall process that we want to make a Dump,cause
the child is a seperate during runtime created process.

Now,when the father decides to create the child process,will allocate memory dynamically.
The father will create the child with all the sections similar to him (cause is the same program
actually) except two sections (maybe more in other applications):Code section.
Of course,IAT section will also not be similar,cause in father is filled with 00's and in
child if filled with redirected calls.

At start,code section of child is filled with 00's.When the child has to start running from OEP,
this will cause an exception to the father,cause as i said,in memory (code section) are 00's.The
father will realize that and will copy the first 1000h bytes to the child.So,in this starting
point,OEP will be between the memory locations that father is filling with the original
decrypted code.The father will also copy an encryption-decryption routine for this memory space
in child,that will be responsible for encrypting during runtime this part of code,when EIP of child
will not be between the ranges of the just copied bytes.Then,father will copy the next original 1000h
bytes to the child, and the next till it fills all the code section of child.Now,the child is
independant to start running alone actually.So,runs the first block of 1000h bytes (which OEP
is inside these memory bounds),and all other blocks of 1000h bytes in child are encrypted.If EIP
passes the limits of that memory space (a call or a jmp or just code execution) the child encrypts
this 1000h bytes blocks and decrypts the requested,that EIP is inside it now.And this thing continues
till the exit of the program.So,cause of those memory copies that happen continually ,and becuase
it is the second version of that techik is called CP2 or Copymem2.

Debug blocker and CP2 prevent from attaching the child with debugger,dissasming it and
Dumping it.

Time for some action now.So,the action is to create this Dump and in
the other tutorial we will fix the IAT.

Ok.Open with Olly the packed,and you should be at EP here:

00447000 > 60               PUSHAD
00447001   E8 00000000      CALL muna.00447006
00447006   5D               POP EBP
00447007   50               PUSH EAX
00447008   51               PUSH ECX
00447009   0FCA             BSWAP EDX
0044700B   F7D2             NOT EDX
0044700D   9C               PUSHFD

Now you remember when I told you that the first 1000h bytes copied to child from father
should contain the OEP?Ok,we will just check how those are copied first.These are copied
to the child with API WriteProcessMemory.Place a breakpoint to that API but not to the first
opcodes of the API,cause Armadillo detects the software breakpoints at those parts of code (
first opcodes of any API call).So,in Olly,in code section right click and find that API in all
names,here is the start of the code of that API:

77E61A94 > 55               PUSH EBP
77E61A95   8BEC             MOV EBP,ESP
77E61A97   51               PUSH ECX
77E61A98   51               PUSH ECX
77E61A99   8B45 0C          MOV EAX,DWORD PTR SS:[EBP+C]
77E61A9C   53               PUSH EBX
77E61A9D   8B5D 14          MOV EBX,DWORD PTR SS:[EBP+14]
77E61AA0   56               PUSH ESI
77E61AA1   8B35 B012E677    MOV ESI,DWORD PTR DS:[<&ntdll.NtProtectV>; ntdll.ZwProtectVirtualMemory
77E61AA7   57               PUSH EDI
77E61AA8   8B7D 08          MOV EDI,DWORD PTR SS:[EBP+8]
77E61AAB   8945 F8          MOV DWORD PTR SS:[EBP-8],EAX
77E61AAE   8D45 14          LEA EAX,DWORD PTR SS:[EBP+14]

Ok,double click at the second PUSH ECX opcode and place the breakpoint there.Now,check all
excpetions in options in Olly (and fill in all ranges in last checkbox) and start executing
the program with Shift+F9.Olly breaks at the breakpoint we set (if any exception,just Shift+F9):

77E61A94 > 55               PUSH EBP
77E61A95   8BEC             MOV EBP,ESP
77E61A97   51               PUSH ECX
77E61A98   51               PUSH ECX                        <------- breaks here
77E61A99   8B45 0C          MOV EAX,DWORD PTR SS:[EBP+C]
77E61A9C   53               PUSH EBX
77E61A9D   8B5D 14          MOV EBX,DWORD PTR SS:[EBP+14]
77E61AA0   56               PUSH ESI
77E61AA1   8B35 B012E677    MOV ESI,DWORD PTR DS:[<&ntdll.NtProtectV>; ntdll.ZwProtectVirtualMemory
77E61AA7   57               PUSH EDI
77E61AA8   8B7D 08          MOV EDI,DWORD PTR SS:[EBP+8]

If we see the stack we see this:

0012B988   0000010C
0012B98C  /0012BC88
0012B990  |00426E05  RETURN to muna.00426E05 from kernel32.WriteProcessMemory
0012B994  |0000010C
0012B998  |00447000  OFFSET muna.<ModuleEntryPoint>
0012B99C  |0012BC80
0012B9A0  |00000002
0012B9A4  |0012BC84
0012B9A8  |0012D220
0012B9AC  |00002710
0012B9B0  |004327C3  muna.004327C3

So,here we have a copy of 2 bytes (0012B9A0 ) from 0012BC80 to the child at 00447000 (0012B998).Well
this is not what we are looking for,we are looking for 1000h bytes copy.Continue with F9 (not shift) two more
time will we break at that API again and see that stack this:

0012BB30  |004268D7  RETURN to muna.004268D7 from kernel32.WriteProcessMemory
0012BB34  |0000009C
0012BB38  |00401000  muna.00401000
0012BB3C  |00992158
0012BB40  |00001000

Yes,this is the first block copied in child in code section.The father copies 1000h bytes from
00992158 (his memory location,we can see it in Olly) to 401000 in child (this we cannot see in the
current Olly).So,401000<OEP<402000.

Again three times F9 and we see those,in sequence we pressed F9:

2nd time:

0012BB30  |004268D7  RETURN to muna.004268D7 from kernel32.WriteProcessMemory
0012BB34  |0000009C
0012BB38  |00403000  muna.00403000
0012BB3C  |00992158
0012BB40  |00001000

3rd time:

0012BB30  |004268D7  RETURN to muna.004268D7 from kernel32.WriteProcessMemory
0012BB34  |0000009C
0012BB38  |00402000  muna.00402000
0012BB3C  |00992158
0012BB40  |00001000

4rth time:

0012BB30  |004268D7  RETURN to muna.004268D7 from kernel32.WriteProcessMemory
0012BB34  |0000009C
0012BB38  |00404000  muna.00404000
0012BB3C  |00992158
0012BB40  |00001000

After that,the father will not copy any other in child,he is done.Now,with F9 the child
is that will run,and Olly becomes useless,since child is not the current process that is
debugging.

At that time,in child memory 401000-402000 is decrypted and all other parts (they are three,remember
when copying?) are decrypted.

So,the idea is first to dump those parts (four parts) when decrypted.So,the only way
to do that is when Olly pauses at the breakpoint we set.So,restart Olly and do the
same things to break in WriteProcessMemory API.When it breaks at the first here

0012BB30  |004268D7  RETURN to muna.004268D7 from kernel32.WriteProcessMemory
0012BB34  |0000009C
0012BB38  |00401000  muna.00401000
0012BB3C  |00992158
0012BB40  |00001000

goto 992158 and you see this:

00992158   55               PUSH EBP
00992159   8BEC             MOV EBP,ESP
0099215B   51               PUSH ECX
0099215C   8B45 08          MOV EAX,DWORD PTR SS:[EBP+8]
0099215F   53               PUSH EBX
00992160   56               PUSH ESI
00992161   57               PUSH EDI
00992162   8945 FC          MOV DWORD PTR SS:[EBP-4],EAX
00992165   C745 08 00000000 MOV DWORD PTR SS:[EBP+8],0
0099216C   60               PUSHAD
0099216D   66:9C            PUSHFW
0099216F   33C9             XOR ECX,ECX
00992171   33C0             XOR EAX,EAX

etc etc.

The useful part ends 1000h bytes later,at 993157 (and 993157 as last byte).So,select this part
of code with mouse.Open another Olly,and reload the packed,and just paste the code in the same memory
location 401000,and save it in a new exe.This is just to save the 1000h bytes.

Do the same for all four parts.ok,now we have the clear code section that starts from 401000 and
ends at 405000.The size of it is 4000h bytes.

Now lets find the OEP.Earlier we saw that 401000<OEP<402000.The trick is to understand that those
memory copies are done when EIP is not in the range of their location.We can see the table that the
father holds those invalid EIP values,that trigger the Copies of memory from father to child.

So,restart the application and set a breakpoit at WaitForDebugEvent,but not at first opcodes cause
Armadillo will detect them.So,we see here the API:

77EAF13C > 55               PUSH EBP
77EAF13D   8BEC             MOV EBP,ESP
77EAF13F   83EC 68          SUB ESP,68
77EAF142   56               PUSH ESI
77EAF143   FF75 0C          PUSH DWORD PTR SS:[EBP+C]
77EAF146   8D45 F8          LEA EAX,DWORD PTR SS:[EBP-8]
77EAF149   50               PUSH EAX
77EAF14A   E8 5BB1FCFF      CALL kernel32.77E7A2AA
77EAF14F   8BF0             MOV ESI,EAX

and we set a breakpoint at PUSH DWORD PTR SS:[EBP+C] opcode.Set also again the breakpoint in the
previous location of WriteProcessMemory API.Run it,it will break to WriteProcessMemory,continue
running till it breaks at WaitForDebugEvent.Check the stack more down,and you see this:

0012BC90  |0042293F  RETURN to muna.0042293F from kernel32.WaitForDebugEvent
0012BC94  |0012CD68  <---- Look this value
0012BC98  |000003E8

The table that holds the EIP values that cause the copies,is at 0012CD68.So go in data window which is
under code and goto 0012CD68 and you can see this:

0012CD68  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0012CD78  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0012CD88  3E 4B F5 77 C8 CD 12 00 9C 00 13 00 3E 4B F5 77  >K貅韧.?.>K貅
0012CD98  D4 CD 12 00 9C 00 13 00 02 00 00 00 8C 00 13 00  酝.?....?.
0012CDA8  00 00 13 00 EC CD 12 00 70 4D F5 77 D4 CD 12 00  ...焱.pM貅酝.
0012CDB8  3E 4B F5 77 F8 CD 12 00 08 06 13 00 70 CE 12 00  >K貅?..p?.
0012CDC8  01 05 13 00 00 00 00 00 00 00 00 00 00 00 00 00  .............

Ok,remove only the WaitForDebugEvent breakpoint and do not touch the data window,so you continue
to see how data at 0012CD68 are changing during execution.Now continue running and Olly breaks
at the first 1000h memory block copy (to 401000).If you now check the table with invalid EIP
values you see this:

0012CD68  01 00 00 00 B8 0F 00 00 C0 0F 00 00 01 00 00 80  ...?..?....?
0012CD78  00 00 00 00 00 00 00 00 16 14 40 00 02 00 00 00  ........@....
0012CD88  00 00 00 00 16 14 40 00 16 14 40 00 00 00 00 00  ....@.@.....
0012CD98  01 E3 55 E1 00 00 00 00 18 3D DA F1 00 00 00 00  阏?...=隈....
0012CDA8  13 00 00 00 DA 0E 51 00 64 3D DA F1 5E CC 4D 80  ...?Q.d=隈^掏?
0012CDB8  00 00 00 00 16 14 40 00 01 00 00 00 01 00 00 00  ....@.......
0012CDC8  01 05 13 00 00 00 00 00 00 00 00 00 00 00 00 00  .............

The only value that seems to be between 401000 and 402000 is 16 14 40 00,which is
the first invalid EIP that causes the first 1000h bytes memory copy and in reverse(00401416)
is the OEP!

Well done.So,make 401416 the new OEP in the exe that you previously saved the clear code section.
Use LordPE for that.

Ok,CP2 defeated.Now we have to seperate the father from the child,cause all other sections
in memory are valid only in the child,and not the father.The father contains 00's in data
section,code section and Import section that original IAT was supposed to be.You can easilly
check that.Eg,goto 401000 and you see this:

00401000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401040  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

Goto fata section at 406000 and you see this:

00406000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406040  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

Goto Import address table section (405000) and you see this:

00405000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405040  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

So,reload the packed in Olly.Set only the same breakpoint we just set earlier at
WriteProcessMemory.Now run it and when it breaks at the first 1000h memory copy,goto the
place where the bytes are copied from:

00992158   55               PUSH EBP
00992159   8BEC             MOV EBP,ESP
0099215B   51               PUSH ECX
0099215C   8B45 08          MOV EAX,DWORD PTR SS:[EBP+8]
0099215F   53               PUSH EBX
00992160   56               PUSH ESI
00992161   57               PUSH EDI
00992162   8945 FC          MOV DWORD PTR SS:[EBP-4],EAX
00992165   C745 08 00000000 MOV DWORD PTR SS:[EBP+8],0
0099216C   60               PUSHAD
0099216D   66:9C            PUSHFW
0099216F   33C9             XOR ECX,ECX
00992171   33C0             XOR EAX,EAX

What we should do before unhooking child from father is make the opcode at OEP a JMP EIP,
so that it will be in an infinitive loop.So,OEP=401416,we can see OEP in the memory location that
will be copied here (at 00992158h + 416h):

0099256E   55               PUSH EBP
0099256F   8BEC             MOV EBP,ESP
00992571   6A FF            PUSH -1
00992573   68 E0504000      PUSH 4050E0
00992578   68 0C204000      PUSH 40200C
0099257D   64:A1 00000000   MOV EAX,DWORD PTR FS:[0]
00992583   50               PUSH EAX
00992584   64:8925 00000000 MOV DWORD PTR FS:[0],ESP

So change opcodes at 0099256E-0099256F from 55h,8Bh to EBh,FEh.
Now just Ctrl+F9 and we are out of the WriteProcessMemory API,here:

004268D7   85C0             TEST EAX,EAX
004268D9   75 4B            JNZ SHORT muna.00426926
004268DB   50               PUSH EAX
004268DC   F7D0             NOT EAX
004268DE   0FC8             BSWAP EAX
004268E0   58               POP EAX
004268E1   73 00            JNB SHORT muna.004268E3

Now check the process list in Olly and find the ID process of the child (black one).Now
find also the call to DebugActiveProcessStop API in your Olly and at 004268D7  write this
code:

004268D7   68 500C0000      PUSH 0C50 <--------------------------------- In  yours may be different
004268DC   E8 5289A877      CALL kernel32.DebugActiveProcessStop

Now execute with F8 those two opcodes.Olly will crash,DO NOT CLOSE OLLY.Let is with
this windows crash message and Open another Olly.Attach at the child process the
new Olly,and you should be here in new Olly:

77F767CE   C3               RETN
77F767CF > CC               INT3
77F767D0   C3               RETN
77F767D1   8B4424 04        MOV EAX,DWORD PTR SS:[ESP+4]
77F767D5   CC               INT3
77F767D6   C2 0400          RETN 4

Now press Don't send in windows error message and close the old Olly.Father is dead,but child
lives in new Olly.

Now,in new Olly (i will call it just Olly now,only one Olly is now),press the "M" button and see
the memory Image of the child.We can see now that the data and Import section are full with data
and no 00's like father:

00405000  90 64 A0 00 A5 8E A0 00 5A 8E A0 00 51 E3 E7 77  ????Z?.Q沌w
00405010  86 66 A0 00 6B 90 E6 77 95 D9 E7 77 F8 5C E7 77  ??k?w?琪?琪
00405020  C8 E0 E7 77 54 C9 E6 77 7E DE E7 77 31 A0 E7 77  揉琪T涉w~掮w1_琪
00405030  FC A7 E7 77 ED 95 E7 77 0C 16 E6 77 68 5A E7 77  ?琪?琪.骥hZ琪
00405040  7E 17 E6 77 43 99 A0 00 37 99 A0 00 7C 68 A0 00  ~骥C?.7?.|h?
00405050  35 69 A0 00 B9 E6 E7 77 C0 30 E9 77 A9 AD E7 77  5i?规琪?轺┉琪
00405060  42 75 E9 77 95 E5 E7 77 49 A9 E7 77 D9 57 E7 77  Bu轺?琪I╃w僮琪
00405070  A7 4F A0 00 80 5B A0 00 94 E4 E7 77 77 79 A0 00  ?????琪wy?
00405080  16 89 E7 77 D2 E2 E7 77 CB 15 E8 77 6B 15 F5 77  ?w意琪?梓k貅

etc etc.

00406000  00 00 00 00 00 00 00 00 00 00 00 00 D5 2B 40 00  ............?@.
00406010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406030  50 6C 65 61 73 65 20 54 72 79 20 41 67 61 69 6E  Please Try Again
00406040  21 20 3A 28 00 00 00 00 42 61 64 20 42 6F 79 21  ! :(....Bad Boy!
00406050  00 00 00 00 43 6F 6E 67 72 61 74 75 6C 61 74 69  ....Congratulati
00406060  6F 6E 73 2E 2E 2E 20 79 6F 75 27 72 65 20 67 6F  ons... you're go
00406070  6F 64 20 69 6E 20 72 65 76 65 72 73 69 6E 67 0A  od in reversing.
00406080  0D 50 6C 65 61 73 65 20 4B 65 79 67 65 6E 20 49  .Please Keygen I

etc etc.

So,now goto OEP=401416 and you see this:

00401416  -EB FE            JMP SHORT muna.00401416
00401418   EC               IN AL,DX                                 ; I/O command
00401419   6A FF            PUSH -1
0040141B   68 E0504000      PUSH muna.004050E0
00401420   68 0C204000      PUSH muna.0040200C
00401425   64:A1 00000000   MOV EAX,DWORD PTR FS:[0]
0040142B   50               PUSH EAX
0040142C   64:8925 00000000 MOV DWORD PTR FS:[0],ESP
00401433   83EC 58          SUB ESP,58

Set new origin at EIP=OEP=00401416h.

Yes,remember the unfinitive loop?Well,don't change that,we will fix the code section
later from the previous clear code section we have,defeating CP2.

Now if you try to dump,does not let you cause if you check the memory you only have
read access:

Memory map
Address    Size       Owner      Section    Contains      Type   Access    Initial   Mapped as

00400000   00001000   muna                                Imag   R         RWE
00401000   00004000   muna       .text                    Imag   R         RWE
00405000   00001000   muna       .rdata                   Imag   R         RWE
00406000   00001000   muna       .data                    Imag   R         RWE
00407000   00040000   muna       .text1     code          Imag   R         RWE
00447000   00010000   muna       .adata     SFX           Imag   R         RWE
00457000   00020000   muna       .data1     data,imports  Imag   R         RWE
00477000   00030000   muna       .pdata                   Imag   R         RWE
004A7000   00001000   muna       .rsrc      resources     Imag   R         RWE

So, at EVERY section (and 4000000 where header is) right click and set Full access.All sections
are RWE now meaning Reading,Writing,Executing access.

Trying again to Dump,you may also cannot.This is becuase the PE header has been erased.So open
a new Olly and reload the packed and just copy-paste the header of packed to 00400000
section.

Now dump it with Olly,having unchecked the IAT fixing.Only thing left to do is just
load the dumped in a new Olly and copy-paste at 401000-405000 the clear copy of the
code section from a previous exe,i suppose you remember when we where dealiong with CP2.

Now the only thing to fix is IAT,and the dump will run just fine.And how can you prove iT?
Well,load the clear (not packed in Olly),goto 405000 and copy all the section to 405000 of the
Dump.Now run it.The Dump runs just fine!

Well in second part (if there will be) I will explain IAT rebuilding...

=======> The only thankz are to Richardo and his tutorialz,cause nothing else helped <========
                    Yes,Greeks and Spanish have something in common ta LasT

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 622
活跃值: (294)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
2
--------------------------------------------------------------------------------
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
KaGra 自豪之作:Armadillo 4.xx Public Build CopyMeM2 及 Debug Blocker 的脱壳
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR

其实,如果不是为了 Richardo 的那篇教程的话,我也不会去写这篇教程。在持续几天的翻译之后,他们向我揭示了 Armadillo 那些所谓的保护。因此,非常感谢他写的那些教程。

我用 Armadillo 4.05 Public Build 来保护了一个程序(exe)。我使用的保护选项有 CopyMeM2+Debug Blocker 及 Memory patching protections。这个特性也包括了 Import table elimination,但是在这
个教程中,我将创建出一个有效的脱壳文件,但是没有重建 IAT。这部分会在稍后放出的这篇教程的第二部分完成。

在附带的 zip 文件中,有一个脱壳的文件(未修复 IAT),被保护的文件和一个未保护的文件。我也很清楚,未保护的文件和脱壳文件的唯一不同就是输入表。所以,如果你用OD载入未保护的文件,然后将区
段 405000 粘贴到脱壳文件中的相应的地方的话,脱壳文件在OD中也能很好的运行。当你读完这篇教程后,你也应该能创建出这样一个脱壳文件,唯一没做的也只剩 IAT 重建了。

使用的工具:OD v1.10,LordPE,OllyDump 插件及 HideOlly 插件。我也修改了OD来对抗 OutputDebugStringA 的使用。

我不会对对他的反调试措施做太多的说明,因为你已经修正了OD,还有隐藏OD的插件。

那么,所谓的 CopyMEM 保护,和 debugger blocking 究竟是些什么呢?

当一个被 Armadillo 保护的程序开始执行时,他会创建另一个进程。这个进程被称做子进程,而一开始的那个进程被称做父进程。所以当你在OD中运行他的时候你可以看看进程列表,你会发现有两个同名称但是 ID 却不同的进程。进程列表中那个红色的进程是当前OD正在调试的进程-父进程,黑色的那个则是子进程。

所以,debugger blocking 实际上是欺负OD这种 Ring-3 级的调试器,使其不能直接调试我们需要脱壳的子进程,导致子进程成为我们调试过程中一个独立的运行进程。

那么,在父进程决定创建子进程的时候,会自动给子进程分配内存。父进程会创建一个所有区段几乎与自己完全一样的子进程(因为他们实际上是同一个程序),但有两个区段不一样:Code section。当然 IAT section 也不会一样,因为父进程填充的是00,而在子进程中填充的是重定位的调用。

一开始的时候,子进程的代码段全是00。当子进程从 OEP 开始运行时,会引发一个异常并被父进程捕获,原因就象我说的那样,内存中代码段中全是00。父进程这时候意识到该把前 1000h 的字节复制给子进程了。所以在这个起始点,OEP 会位于父进程填充的原始的解密过的代码所在的内存区域中。父进程也将复制一段针对这段内存的加密解密程序到子进程中,所以当子进程的 EIP 超出这段内存区域时,这部分代码就会被重新加密。然后,父进程在复制下一段原始的 1000h 的字节给子进程,并且继续这样直到子进程的代码段都被填充过。现在子进程已经可以独立运行了。所以运行完第一块 1000h 的字节后(OEP 所在的那一块),其他部分的子进程还是被加密的。当 EIP 超出这段范围时(某个调用或跳转或仅仅是代码的执行),子进程将加密这 1000h 的字节块,然后解密需要的部分,EIP 所在的那一段。这样的过程会一直持续到子进程终止运行。因此,根据这种持续发生的内存复制,这种再版的保护被称为 CP2 或是 Copymem2。

Debug blocker 和 CP2 防止了子进程被调试器附加,被反汇编还有被脱壳。

现在是该做些什么东西的时候了。而我们要做的就是创建一个脱壳文件,然后在下篇教程中修复 IAT。

我们用OD载入被保护的文件,你会停在这个 EP 处:

00447000 > 60               PUSHAD
00447001   E8 00000000      CALL muna.00447006
00447006   5D               POP EBP
00447007   50               PUSH EAX
00447008   51               PUSH ECX
00447009   0FCA             BSWAP EDX
0044700B   F7D2             NOT EDX
0044700D   9C               PUSHFD

还记得我告诉过你父进程会复制包含 OEP 在内的 1000h 的字节给子进程吗?那么我们来看看他们是怎么被复制的。他们的复制是通过调用 API WriteProcessMemory 来完成的。在这个 API 上下个断点,但是不要下在第一个指令上,因为 Armadillo 会检测这些代码部分的软件断点(每个 API 调用的第一个指令)。所以,我们在OD中右击 code section 然后找出所有的 API 名称,下面是这个 API 的开始点:

77E61A94 > 55               PUSH EBP
77E61A95   8BEC             MOV EBP,ESP
77E61A97   51               PUSH ECX
77E61A98   51               PUSH ECX
77E61A99   8B45 0C          MOV EAX,DWORD PTR SS:[EBP+C]
77E61A9C   53               PUSH EBX
77E61A9D   8B5D 14          MOV EBX,DWORD PTR SS:[EBP+14]
77E61AA0   56               PUSH ESI
77E61AA1   8B35 B012E677    MOV ESI,DWORD PTR DS:[<&ntdll.NtProtectV>; ntdll.ZwProtectVirtualMemory
77E61AA7   57               PUSH EDI
77E61AA8   8B7D 08          MOV EDI,DWORD PTR SS:[EBP+8]
77E61AAB   8945 F8          MOV DWORD PTR SS:[EBP-8],EAX
77E61AAE   8D45 14          LEA EAX,DWORD PTR SS:[EBP+14]

现在,双击第二个 PUSH ECX 指令来下个断点。然后,忽略所有异常(并且在最后的复选框中要填入全部的范围)用 Shift+F9 开始执行。OD会停在我们下断点的地方的(如果出现什么异常的话,按 Shift+F9 通过):

77E61A94 > 55               PUSH EBP
77E61A95   8BEC             MOV EBP,ESP
77E61A97   51               PUSH ECX
77E61A98   51               PUSH ECX      <------- 断在了这里
77E61A99   8B45 0C          MOV EAX,DWORD PTR SS:[EBP+C]
77E61A9C   53               PUSH EBX
77E61A9D   8B5D 14          MOV EBX,DWORD PTR SS:[EBP+14]
77E61AA0   56               PUSH ESI
77E61AA1   8B35 B012E677    MOV ESI,DWORD PTR DS:[<&ntdll.NtProtectV>; ntdll.ZwProtectVirtualMemory
77E61AA7   57               PUSH EDI
77E61AA8   8B7D 08          MOV EDI,DWORD PTR SS:[EBP+8]

在堆栈中,我们可以看到

0012B988   0000010C
0012B98C  /0012BC88
0012B990  |00426E05  返回到 muna.00426E05 来自 kernel32.WriteProcessMemory
0012B994  |0000010C
0012B998  |00447000  OFFSET muna.<ModuleEntryPoint>
0012B99C  |0012BC80  <-这里
0012B9A0  |00000002  <-这里
0012B9A4  |0012BC84
0012B9A8  |0012D220
0012B9AC  |00002710
0012B9B0  |004327C3  muna.004327C3

看,现在已经有 2 个字节 (0012B9A0 ) 被从 0012BC80 复制到了子进程中的 00447000 (0012B998)。不过着并不是我们需要的,我们需要的是 1000h 个字节的复制。使用 F9 继续(不是 shift)两次,我们再次停在了这里,再看看堆栈会看见这些:

0012BB30  |004268D7  返回到 muna.004268D7 来自 kernel32.WriteProcessMemory
0012BB34  |0000009C
0012BB38  |00401000  muna.00401000
0012BB3C  |00992158
0012BB40  |00001000  <-这里

不错,这就是复制到子进程代码段中的第一个块。父进程从 00992158 (他自己的内存段,我们可以在OD中看到)复制里了 1000h 的字节到子进程的 401000 处(这个我们在当前的OD中看不见)。所以,401000<OEP<402000。

再接下来的三次 F9 后我们也看见了这些,按次序列出:

第2次:

0012BB30  |004268D7  返回到 muna.004268D7 来自 kernel32.WriteProcessMemory
0012BB34  |0000009C
0012BB38  |00403000  muna.00403000
0012BB3C  |00992158
0012BB40  |00001000

第3次:

0012BB30  |004268D7  返回到 muna.004268D7 来自 kernel32.WriteProcessMemory
0012BB34  |0000009C
0012BB38  |00402000  muna.00402000
0012BB3C  |00992158
0012BB40  |00001000

第4次:

0012BB30  |004268D7  返回到 muna.004268D7 来自 kernel32.WriteProcessMemory
0012BB34  |0000009C
0012BB38  |00404000  muna.00404000
0012BB3C  |00992158
0012BB40  |00001000

在这之后父进程就不再复制什么东西到子进程中了,他的任务完成了。如果你现在再按 F9 的话,子进程就会运行,而OD此时就显得爱莫能助,因为当前被调试的进程并不是子进程。

在那时,子进程的内存区域 401000-402000 是已解密的,其他几个部分也是的(记得他复制了三次吗?)。

所以,我们现在会想到先去脱下那四个已解密的部分,而且也只能在OD停在我们设置的断点的时候来做。那么按上面的步骤重来一次吧。当我们停在第一次复制 1000h 的地方的时候:

0012BB30  |004268D7  返回到 muna.004268D7 来自 kernel32.WriteProcessMemory
0012BB34  |0000009C
0012BB38  |00401000  muna.00401000
0012BB3C  |00992158
0012BB40  |00001000

跳转到 992158 你会看见这些:

00992158   55               PUSH EBP
00992159   8BEC             MOV EBP,ESP
0099215B   51               PUSH ECX
0099215C   8B45 08          MOV EAX,DWORD PTR SS:[EBP+8]
0099215F   53               PUSH EBX
00992160   56               PUSH ESI
00992161   57               PUSH EDI
00992162   8945 FC          MOV DWORD PTR SS:[EBP-4],EAX
00992165   C745 08 00000000 MOV DWORD PTR SS:[EBP+8],0
0099216C   60               PUSHAD
0099216D   66:9C            PUSHFW
0099216F   33C9             XOR ECX,ECX
00992171   33C0             XOR EAX,EAX

等等

有用的部分是下面的 1000h 的字节,到 993157 为止(993157 就是我们需要的最后一个字节)。那么,我们用鼠标选中这部分代码。然后打开另外一个OD,并载入被保护的文件,把刚才复制的字节粘贴到内存段 401000 中相同的地方,然后保存它。这样我们就有了 1000h 的字节。

对下面四部分也这样做。所以,我们现在有了从 401000 到 405000 之间的正确的代码。他的大小是 4000h 的字节。

那么现在我们来找 OEP。前面我们得知 401000<OEP<402000。但是你需要知道的是他们是在 EIP 不在他们所在的位置时才被完成的。我们可以在列表中看见父进程还保留着那些无效的 EIP 值,他们是父进程向子进程复制数据的引发器。

现在,我们重来并在 WaitForDebugEvent 上下个断点,但是同样不要下在第一条指令上。我们先来看看这个 API:

77EAF13C > 55               PUSH EBP
77EAF13D   8BEC             MOV EBP,ESP
77EAF13F   83EC 68          SUB ESP,68
77EAF142   56               PUSH ESI
77EAF143   FF75 0C          PUSH DWORD PTR SS:[EBP+C]
77EAF146   8D45 F8          LEA EAX,DWORD PTR SS:[EBP-8]
77EAF149   50               PUSH EAX
77EAF14A   E8 5BB1FCFF      CALL kernel32.77E7A2AA
77EAF14F   8BF0             MOV ESI,EAX

我们在 PUSH DWORD PTR SS:[EBP+C] 指令上设断点。还有不要忘了在 WriteProcessMemory 上设断点。运行,它会停在 WriteProcessMemory,不过我们继续,直到他停在了 WaitForDebugEvent。在堆栈中找找你会发现:

0012BC90  |0042293F  返回到 muna.0042293F 来自 kernel32.WaitForDebugEvent
0012BC94  |0012CD68  <---- 看见这个了?
0012BC98  |000003E8

这里是保留那些引发复制的 EIP 值的地方,是在 0012CD68。那么我们在数据窗口中追随他:

0012CD68  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0012CD78  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0012CD88  3E 4B F5 77 C8 CD 12 00 9C 00 13 00 3E 4B F5 77  >K貅韧.?.>K貅
0012CD98  D4 CD 12 00 9C 00 13 00 02 00 00 00 8C 00 13 00  酝.?....?.
0012CDA8  00 00 13 00 EC CD 12 00 70 4D F5 77 D4 CD 12 00  ...焱.pM貅酝.
0012CDB8  3E 4B F5 77 F8 CD 12 00 08 06 13 00 70 CE 12 00  >K貅?..p?.
0012CDC8  01 05 13 00 00 00 00 00 00 00 00 00 00 00 00 00  .............

现在我们删除 WaitForDebugEvent 上的断点,并且不要碰数据窗口,这样你就能继续看见 0012CD68 处的数据的变化了。继续执行,然后OD会暂停在第一次 1000h 内存块的复制的时候(到 401000)。现在你再看看数据窗口你会看见:

0012CD68  01 00 00 00 B8 0F 00 00 C0 0F 00 00 01 00 00 80  ...?..?....?
0012CD78  00 00 00 00 00 00 00 00 16 14 40 00 02 00 00 00  ........@....
0012CD88  00 00 00 00 16 14 40 00 16 14 40 00 00 00 00 00  ....@.@.....
0012CD98  01 E3 55 E1 00 00 00 00 18 3D DA F1 00 00 00 00  阏?...=隈....
0012CDA8  13 00 00 00 DA 0E 51 00 64 3D DA F1 5E CC 4D 80  ...?Q.d=隈^掏?
0012CDB8  00 00 00 00 16 14 40 00 01 00 00 00 01 00 00 00  ....@.......
0012CDC8  01 05 13 00 00 00 00 00 00 00 00 00 00 00 00 00  .............

在这么多的数据中介于 401000 到 402000 之间的好象也只有 16 14 40 00 了,他就是引发第一次 1000h 的字节的复制的第一个无效的 EIP,那么反而言之(00401416)就是 OEP!

很好,让 401416 作为你前面保存的正确的代码的可执行文件的新的 OEP。LordPE 就可以完成。

现在,CP2 已经失效了。我们已经把父进程从子进程中去除,因为内存中的所有区段都只对子进程有效,对父进程则无效。父进程的数据段、代码段和原始输入表所应在的输入表段全是00。这个可以很容易的知道。例如,跳转到 401000 你会看见这个:

00401000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401040  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

跳转到数据段 406000 你会看见这个:

00406000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406040  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

跳转到输入表段 405000 你会看见这个:

00405000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405040  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

所以在OD中重新载入被保护的文件。仅设置在 WriteProcessMemory 上的断点。运行他后中断在第一次 1000h 的字节的复制,转到要复制的字节的来源的地方:

00992158   55               PUSH EBP
00992159   8BEC             MOV EBP,ESP
0099215B   51               PUSH ECX
0099215C   8B45 08          MOV EAX,DWORD PTR SS:[EBP+8]
0099215F   53               PUSH EBX
00992160   56               PUSH ESI
00992161   57               PUSH EDI
00992162   8945 FC          MOV DWORD PTR SS:[EBP-4],EAX
00992165   C745 08 00000000 MOV DWORD PTR SS:[EBP+8],0
0099216C   60               PUSHAD
0099216D   66:9C            PUSHFW
0099216F   33C9             XOR ECX,ECX
00992171   33C0             XOR EAX,EAX

我们现在要做的是通过把 OEP 处的指令改为 JMP EIP,来解除子进程对父进程的依赖,所以要让他无限死循环。我们去要复制的 OEP 所在的地方(00401416h-00401000h+00992158h=0099256E):

0099256E   55               PUSH EBP
0099256F   8BEC             MOV EBP,ESP
00992571   6A FF            PUSH -1
00992573   68 E0504000      PUSH 4050E0
00992578   68 0C204000      PUSH 40200C
0099257D   64:A1 00000000   MOV EAX,DWORD PTR FS:[0]
00992583   50               PUSH EAX
00992584   64:8925 00000000 MOV DWORD PTR FS:[0],ESP

把 0099256E-0099256F 之间的字节从 55h,8Bh 改为 EBh,FEh后,我们按 Ctrl+F9 返回程序领空,这里:

004268D7   85C0             TEST EAX,EAX
004268D9   75 4B            JNZ SHORT muna.00426926
004268DB   50               PUSH EAX
004268DC   F7D0             NOT EAX
004268DE   0FC8             BSWAP EAX
004268E0   58               POP EAX
004268E1   73 00            JNB SHORT muna.004268E3

现在去进程列表中记下子进程的 ID(黑色的那个)。然后再在你的OD中找到 DebugActiveProcessStop API 的地址,并在 004268D7 写下这些代码:

004268D7   68 500C0000      PUSH 0C50 <--------------------------------- 这个可能与你的不同(译者:这东西可能是父进程的PID)
004268DC   E8 5289A877      CALL kernel32.DebugActiveProcessStop

然后按 F8 单步执行两次。OD会崩溃,这时请不要关闭这个OD。暂时不要管那个崩溃信息的窗口,开启一个新的OD去附加子进程,然后你会停在这里:

77F767CE   C3               RETN
77F767CF > CC               INT3
77F767D0   C3               RETN
77F767D1   8B4424 04        MOV EAX,DWORD PTR SS:[ESP+4]
77F767D5   CC               INT3
77F767D6   C2 0400          RETN 4

现在按下错误消息窗口中的 不发送 按钮来关闭前一个OD。现在父进程挂了,但子进程在新的OD中留了下来。

现在在新的OD中(以后我就直接称他为OD,因为现在只有一个OD了),按下 "M" 键来看看子进程的内存映像。我们可以看见现在子进程的数据段和输入表段都有了数据,不象父进程那样全是00了:

00405000  90 64 A0 00 A5 8E A0 00 5A 8E A0 00 51 E3 E7 77  ????Z?.Q沌w
00405010  86 66 A0 00 6B 90 E6 77 95 D9 E7 77 F8 5C E7 77  ??k?w?琪?琪
00405020  C8 E0 E7 77 54 C9 E6 77 7E DE E7 77 31 A0 E7 77  揉琪T涉w~掮w1_琪
00405030  FC A7 E7 77 ED 95 E7 77 0C 16 E6 77 68 5A E7 77  ?琪?琪.骥hZ琪
00405040  7E 17 E6 77 43 99 A0 00 37 99 A0 00 7C 68 A0 00  ~骥C?.7?.|h?
00405050  35 69 A0 00 B9 E6 E7 77 C0 30 E9 77 A9 AD E7 77  5i?规琪?轺┉琪
00405060  42 75 E9 77 95 E5 E7 77 49 A9 E7 77 D9 57 E7 77  Bu轺?琪I╃w僮琪
00405070  A7 4F A0 00 80 5B A0 00 94 E4 E7 77 77 79 A0 00  ?????琪wy?
00405080  16 89 E7 77 D2 E2 E7 77 CB 15 E8 77 6B 15 F5 77  ?w意琪?梓k貅

等等

00406000  00 00 00 00 00 00 00 00 00 00 00 00 D5 2B 40 00  ............?@.
00406010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00406030  50 6C 65 61 73 65 20 54 72 79 20 41 67 61 69 6E  Please Try Again
00406040  21 20 3A 28 00 00 00 00 42 61 64 20 42 6F 79 21  ! :(....Bad Boy!
00406050  00 00 00 00 43 6F 6E 67 72 61 74 75 6C 61 74 69  ....Congratulati
00406060  6F 6E 73 2E 2E 2E 20 79 6F 75 27 72 65 20 67 6F  ons... you're go
00406070  6F 64 20 69 6E 20 72 65 76 65 72 73 69 6E 67 0A  od in reversing.
00406080  0D 50 6C 65 61 73 65 20 4B 65 79 67 65 6E 20 49  .Please Keygen I

等等

现在我们去 OEP=401416 你会看见:

00401416  -EB FE            JMP SHORT muna.00401416
00401418   EC               IN AL,DX                                 ; I/O 命令
00401419   6A FF            PUSH -1
0040141B   68 E0504000      PUSH muna.004050E0
00401420   68 0C204000      PUSH muna.0040200C
00401425   64:A1 00000000   MOV EAX,DWORD PTR FS:[0]
0040142B   50               PUSH EAX
0040142C   64:8925 00000000 MOV DWORD PTR FS:[0],ESP
00401433   83EC 58          SUB ESP,58

设置 EIP=OEP=00401416h.

恩,记得我们设的那个无限循环吗?不过不要修改他,我们过会用我们前面保存的正确的代码中恢复他。

如果你现在想脱壳的话,你会发现困难重重,因为你看下内存就会知道,现在你对他们只有读取的权利:

内存映像
地址       大小       所有者     区段       包含          类型   访问      初始访问   映射为

00400000   00001000   muna                                Imag   R         RWE
00401000   00004000   muna       .text                    Imag   R         RWE
00405000   00001000   muna       .rdata                   Imag   R         RWE
00406000   00001000   muna       .data                    Imag   R         RWE
00407000   00040000   muna       .text1     code          Imag   R         RWE
00447000   00010000   muna       .adata     SFX           Imag   R         RWE
00457000   00020000   muna       .data1     data,imports  Imag   R         RWE
00477000   00030000   muna       .pdata                   Imag   R         RWE
004A7000   00001000   muna       .rsrc      resources     Imag   R         RWE

所以,在每个区段上(包括 400000)右击并设置为完全访问。所有的区段都是 RWE 即为 读取、写入、执行。

再试着脱一次看看,可能还是不行。因为 PE header 被檫除了。所以打开一个新的OD,重新载入被保护的文件,然后把他的 00400000 段复制过来。

现在用OD的插件来脱吧,不要选 IAT 修复。然后用一个新的OD载入他,并把我们的那个正确的文件的 401000-405000 处的代码复制过来。我猜你现在应该还记得我们是在哪里处理 CP2 的吧?

现在唯一要修复的就是 IAT 了,虽然这个脱壳文件也能运行的很好。不信?
那好,载入那个未加壳的文件,把 405000 段中的所有东西都复制到脱壳文件的 405000 段中。试着运行一下,看见了吗?他运行的很好。

好了下一部分(如果有的话),我来讲解 IAT 的重建...

=======> 仅感谢 Richardo 和他的教程,因为没有其他的帮助 <========
              不过希腊语和西班牙语还是有些相同的
2005-5-4 13:41
0
雪    币: 98847
活跃值: (201074)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
3
辛苦了
2005-5-4 14:56
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
UPX
4
KaGra的教程本来就写得比较难看
现在看来是越来越难看了
2005-5-4 15:02
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
5
2楼辛苦!
2005-5-5 12:48
0
雪    币: 622
活跃值: (294)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
6
鸡蛋壳,你什么时候能找到下篇~~~~~
^_^
2005-5-5 22:40
0
雪    币: 427
活跃值: (412)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
最初由 无聊的菜鸟 发布
鸡蛋壳,你什么时候能找到下篇~~~~~
^_^


找一篇是一篇
2005-5-6 09:28
0
雪    币: 383
活跃值: (786)
能力值: ( LV12,RANK:730 )
在线值:
发帖
回帖
粉丝
8
最想看的还是对 CC 保护的通用拆解教程...,这些只是练手认识而已,不过还是 thks 翻译者
2005-5-7 16:13
0
游客
登录 | 注册 方可回帖
返回
//