我用?上翻诅 Ru->EN 弈的不是很?? 腠邋字很多但彦面很多都是softICE的Debug方法 Sice我不熟 所以?是希望大家翻一下 THX
目前只整理到4章 那?我看我?弈Ru->EN
大?家?忙一下 EN->CH
如果照英文文法一定看不懂 所以希望熟SoftICE的大大?一下 THX

-----------------------------------------
=======================================================================
=============手??? (NFSU2 - Safedisc v 3.xx)===================
=======================================================================
作者: mr_magic
弈傥: rep0A
日期: 3.12.2004
目?: Speed2.exe
大小: 5.987.981 Bytes
工具: SoftIce, IceExt 0.65, PEditor 1.7, Procdump 1.6, Imprec 1.6f, Hex Workshop, Code Fusion
肺?: ??
Mini Image & 原始 speed2.exe
9c4K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4y4W2L8X3c8K6M7r3q4U0k6g2)9J5k6h3y4G2L8g2)9J5c8X3k6A6L8r3g2Q4x3V1j5&6K9o6x3^5M7r3R3`.
SafeDisc 3 RU&EN Docs
dfeK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4y4W2L8X3c8K6M7r3q4U0k6g2)9J5k6h3y4G2L8g2)9J5c8X3k6A6L8r3g2Q4x3V1k6F1K9s2u0@1y4X3t1`.1. 前言
=================
?先??原始 SafeDisc CD 如果?CD的? 可至 GameCopyWorld 或其他地方下蒌一?可??咣?的 Mini Image
用 Daemon Tools 或 Alcohol 120% ?模?.
2. ??
==================
以PE??器檫??段, 已知stxt774跟stxt371?Safedisc的?段
stxt774 ?防罪劫?
stxt371 ?Loader?段
完全清除safeDisc後可?他去除
在蒌入Debug前 ?先把 "代瘁?段 .text(.Code) 跟Import Table ?段 .rdata 的?段加入可?的?性


3. Restoration Import
===============================
With the explanation of the restoration of import I will describe only about necessary, since this did not change after my
last splint
Well it is agreeable, give let us look on YE.P. Here we will use PEditor for that, so that SoftIce(.SI) would stop after the
load of program. For this press on "break'n'enter" and place point of discontinuity to Int03.
:bpint3
If we now press on "RUN", softays will show us this:
0093309E 55 PUSH EBP
0093309F 8BEC MOV EBP,ESP
009330A1 60 PUSHAD
009330A2 BB 9E309300 MOV EBX,OFFSET speed2.{ModuleEntryPoint}
009330A7 33C9 XOR ECX,ECX
009330A9 8A0D 3D309300 MOV CL,BYTE PTR DS:[93303D]
009330AF 85C9 TEST ECX,ECX
009330B1 74 0C JE speed2.009330BF
009330B3 B8 13319300 MOV EAX,speed2.00933113
009330B8 2BC3 SUB EAX,EBX
009330BA 83E8 05 SUB EAX,5
009330BD EB 0E JMP speed2.009330CD
009330BF 51 PUSH ECX
009330C0 B9 59319300 MOV ECX,speed2.00933159
009330C5 8BC1 MOV EAX,ECX
009330C7 2BC3 SUB EAX,EBX
009330C9 0341 01 ADD EAX,DWORD PTR DS:[ECX+1]
009330CC 59 POP ECX
009330CD C603 E9 MOV BYTE PTR DS:[EBX],0E9
009330D0 8943 01 MOV DWORD PTR DS:[EBX+1],EAX
009330D3 51 PUSH ECX
009330D4 68 09309300 PUSH 00933009
009330D9 33C0 XOR EAX,EAX
009330DB 85C9 TEST ECX,ECX
009330DD 74 05 JE 009330E4
009330DF 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
009330E2 EB 00 JMP 009330E4
009330E4 50 PUSH EAX
009330E5 E8 76000000 CALL 00933160 ;解?矿代瘁?理
009330EA 83C4 08 ADD ESP,8
009330ED 59 POP ECX
009330EE 83F8 00 CMP EAX,0 ;??解?矿是否有邋锗?
009330F1 74 1C JE 0093310F ;正催?跳
009330F3 C603 C2 MOV BYTE PTR DS:[EBX],0C2
009330F6 C643 01 0C MOV BYTE PTR DS:[EBX+1],0C
009330FA 85C9 TEST ECX,ECX
009330FC 74 09 JE 00933107
009330FE 61 POPAD
009330FF 5D POP EBP
00933100 B8 00000000 MOV EAX,0
00933105 EB 97 JMP {ModuleEntryPoint}
00933107 50 PUSH EAX
00933108 A1 29309300 MOV EAX,DWORD PTR DS:[933029]
0093310D FFD0 CALL EAX
0093310F 61 POPAD ;the stack clean
00933110 5D POP EBP ; ""
00933111 EB 46 JMP 00933159 ;擂理跳弈
00933113 807C24 08 00 CMP BYTE PTR SS:[ESP+8],0
00933118 75 3F JNZ 00933159
0093311A 51 PUSH ECX
0093311B 8B4C24 04 MOV ECX,DWORD PTR SS:[ESP+4]
0093311F 890D 53319300 MOV DWORD PTR DS:[933153],ECX
00933125 B9 31319300 MOV ECX,00933131
0093312A 894C24 04 MOV DWORD PTR SS:[ESP+4],ECX
0093312E 59 POP ECX
0093312F EB 28 JMP 00933159
00933131 50 PUSH EAX
00933132 B8 2D309300 MOV EAX,0093302D
00933137 FF70 08 PUSH DWORD PTR DS:[EAX+8]
0093313A 8B40 0C MOV EAX,DWORD PTR DS:[EAX+C]
0093313D FFD0 CALL EAX
0093313F B8 2D309300 MOV EAX,0093302D
00933144 FF30 PUSH DWORD PTR DS:[EAX]
00933146 8B40 04 MOV EAX,DWORD PTR DS:[EAX+4]
00933149 FFD0 CALL EAX
0093314B 58 POP EAX
0093314C FF35 53319300 PUSH DWORD PTR DS:[933153]
00933152 C3 RETN
00933153 72 16 JB 0093316B
00933155 61 POPAD
00933156 1360 0D ADC ESP,DWORD PTR DS:[EAX+D]
00933159 E9 9388E2FF JMP 0075B9F1 ;前往 OEP!!!
Thus nothing new after Safedisc v2. No, there is one small change: We can place breykpoynt directly on the leap on OEP.
Safedisc this will no longer note (31 fellows, you ukhud'sheli your zashitu:D) means
:bpx #00933159
Carefully, before we will begin to go further, we must change int3 which we they placed in EP to the initial byte.
:eb eip 55
Now we press to F5, we jingle, we press one time F8 and now we are found on OEP. Voobshcheto would be everything good, all
sections are unpacked and we can dampit', if Safediss did not put to us stick in the wheels... pear??? Hehe, let's fix dat...
first we must it will care about not the complete import.
That the import is cut, it is possible to learn very easily, if we look on IAT (kotora4 it is located in the begin section ".rdata").

RVA to API to functions must be read to back on before, this indicates that the address of the first import on the picture it
is equal to 77E53835. This address on my OS belongs to Kernel32.RaiseException. We immediately see that import Kernel32 it is
cut, it means we should it restore. Unfortunately this does not completely decrease our work...
Entire import, which begins with 0174/0175 this the cut import. We will memorize this for our import fiksiruyushigo of the
code.
Ktomu-zhe we will memorize in what part of IAT it is encountered this cut import. In me this the approximately first 500h
bytes.
Kak was already described in my past article, we wake to write our code in PE Header+500h (or to enter if you more greatly
pleases itself to use Code Snippet Creator or Hiew).
In order to to understand the following steps, I advise you to pozakhodit' into the nekot.orye perenapravlennye calls. Call
relating to the first perenapravlennomu import in IAT (00783004) appears thus:

If we into it enter we let us see here this:
To procedure Safedisc-a, which removes that cut RVA and is caused the appropriate import, 3 parameters are transferred. 2 of
them we can see on the picture. This is two PUSH-a(0174D582, 0174D58A). The third is transferred by "invisible" through the
stack. This is address, out of which was caused our cut import + 6, consequently address afterward "Call [ 00783004 ]".
So occurs therefore- that Call this nothing another as leap and Push $the address of the leap + 6' in one. This fact forces
us to restore in the section.text not only IAT(kak in many zashit), but also Call [ref]'.
Some imports appear for us equally after perenapravlenniya, therefore- that they indicate the identical address in IAT. Since
procedure Safedisc-a for restoring the import includes address Call[ref]' into the calculation, different API- functions
are caused.
Give let us look to procedure itself, which begins with 6678D3BA. If we are sufficient to for long treysim, we will note that
these 3 places those more meant:
Here it is checked, there was obrabatyvayushchayusya RVA already vostanovlenna. If no, we pass leap and she
vostanavlivayetsya. If yes, that is used already imeyusheyesya. We propatchim this procedure so as to our RVA constantly
vostannavlivalis' renovate. For this we will make from the conditional leap unconditional. This will give to us lut'she to
feel itself ;)
As we see, the second checking is carried out, it will be restored before the fact RVA. (here we zanopim leap). In conclusion
to stack is transferred through PUSH number DLL and functions, which before this were calculated from our three parameters
and RVA is restored in represented Call-e.
This place for us is the most interesting, therefore- that this is the end of the procedure. Stack is cleaned and when we
treysim through RET, we are found in the beginning of correct API function. This means that before we protreysim through RET,
upper dword in our stack is that most correct RVA for our import. This we is utilized in our code. For this we will write on
address 6678D6AB
My let us divide our code for restoring the import into two parts. The first is necessary therefore- that programmers from
Macrovision they noted trick with three parameters. Thus first we must we wake write down in not the necessary place
temporary, restored IAT, in which there are no cut imports. We will later write down it above the old, which to us is still
necessary,
in order to to restore section.text. We will search entire section.text to object Call[ref]'.s, which cause those cut RVA
and to correct their purposeful addresses on the new symbolic addresses of temporary IAT, so in order to they posli of
perepisaniya IAT caused correct import.
As the suitable place for the creation by the temporary IAT I see Safedisc Loader Section. Thus we again will look in this
section, in order to to have all values for our code.
_ReturnNachSafedisc: ;(_To vozvrashcheniye Safedisc)
mov esp, dword ptr [ebp+0C] ;Stack cleans, like the function
popad ;at the end of procedure Safedisc-a which ended
popfd ;izza of leap.
pop edx ;Preserves the correct RVA in edx
cmp dword ptr [esp], 00400500 ;would leave we in the case of RETurn-a
jl _KorrigiereStack ;in our code?
cmp dword ptr [esp], 00401000 ;If no, that kor.pigiruyet stack.
ja _KorrigiereStack ;(this becomes necessary, therefore-that
ret ;we is utilized additional PUSH
_KorrigiereStack: ;(_Vosstanavlivayu Stack)
add esp, 4 ;in the second part of our code,
ret ;in order to to place exit point.
_CODEPART1:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;; Creation by the temporary IAT ;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ecx, 00782FFC ;beginning IAT-4
mov ebx, 00932FFC ;Safedisc Loader Section-4
_Start: ;(_Start:)
add ecx, 4 ;I make further with the following RVA
add ebx, 4 ;I also increase the address of our temporary IAT
cmp ecx, 00783500 ;we already processed 500h it was byte?
ja _EndeBuildIAT ;(_End Compilations IAT)
mov edx, dword ptr [ecx] ;I put RVA the processed import in edx
cmp edx, 01740000 ;RVA in
jl _BuildIAT^ ;(_Compilation IAT)
cmp edx, 01760000 ;Safedisc Range?
ja _BuildIAT ;(_Compilation IAT)
call edx ;if yes, I cause import in order to to leave the correct RVA
_BuildIAT: ;(_Compilation IAT)
mov dword ptr [ebx], edx ;I put the correct RVA in the temporary
jmp _Start
_EndeBuildIAT: ;(_End Compilations IAT)
jmp _CODEPART2
_CODEPART2:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;; Restoration Call [.ref]s ;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax, 00401000 ;beginning of the section .text
_SucheNachCallRefs: ;(_Search CallRefs)
cmp word ptr [eax], 15FF ;The first two bytes belong to the urgent function FF15?
je _CallRefGefunden ;(_CallRef found) If yes, I check Call [.ref]
_SucheNachCallRefsLoop: ;(_Search CallRefsLoop)
inc eax ;If no, I make further with the following function
cmp eax, 00782FFF ;We reached the end of the section .text?
jne _SucheNachCallRefs ;(_Search CallRefs)
jmp _AlleCallRefsGefixt ;(_Everything CallRefs They are restored)
_CallRefGefunden: ;(_found CallRef)
cmp dword ptr [eax+02], 00783000 ;Read address, in
jl _SucheNachCallRefsLoop ;(_Search CallRefsLoop)
cmp dword ptr [eax+02], 00783500 ;the first 500h is byte by our IAT?
ja _SucheNachCallRefsLoop ;(_Search CallRefsLoop)
_CheckobGemangleterCallRef: ;(_CheckobGemangleterCallRef)
mov ecx, dword ptr [eax+02] ;I put the address of import in IAT in ecx
mov ecx, dword ptr [ecx] ;I put RVA urgent import into ecx
cmp ecx, 01740000 ;RVA in
jl _SucheNachCallRefsLoop ;(_Search CallRefsLoop)
cmp ecx, 01760000 ;Safedisc Range?
ja _SucheNachCallRefsLoop ;(_Search CallRefsLoop)
Push _FixCallRefReturnPoint ;if yes, I place our Return Point
add eax, 6 ;I calculate 3. Parameter (Call [.ref] Offset+6)
push eax ;And push-uh it
sub eax, 6 ;I again place beginning Call [.ref]s in eax
jmp ecx ;and I carry out SD Routine, in order to to leave the correct RVA
_FixCallRefReturnPoint: ;(_Restoration ReturnPoint-aCallRef-a)
mov ebx, 00933000 ;I put the beginning of the temporary IAT in ebx
_FixCallRefLoop: ;(_Restoration CallRefLoop-a)
cmp dword ptr [ebx], edx ;I search for the urgent RVA in the the temporary IAT
je _FixCallRef ;(_Restoration CallRef-a)
add ebx, 4 ;I check the following import in the the temporary IAT
cmp ebx, 00933500 ;we reached the end of the temporary IAT?
jl _FixCallRefLoop ;if no, I make further
jmp eip ;In other case I transfer control to the search for the errors
_FixCallRef: ;(_Restoration CallRef-a)
sub ebx, 00933000 ;I put symbolic address measured in the beginning IAT in ebx
add ebx, 00783000 ;and to the future address if temporary IAT was kopirovana in the correct place
mov dword ptr [eax+02], ebx ;and I renew Call[.ref ] with the new address of the import
jmp _SucheNachCallRefsLoop
_AlleCallRefsGefixt: ;(_Everything CallRef-bi They are restored)
jmp _CODEPART3
Unfortunately the import was of perenapravlen not only this means. There is still the second method. There exist Longjumps,
which were once Call [.ref]-ami, which now cause section stx774. in principle this we could be and Call-bi to Jumptables, but
this is not in NFSU2. We can see very easily this, therefore- that byte after leap always Junk Byte therefore- that initially
standing at this place Call [ref] was one byte longer than leap. Caused izza of leap procedure Safedisc-a constantly jumps
over this byte. Example for similar Long Jump-a:
We see that the instruction after leap does not have a sense. This Voobshcheto must appear thus:
If we protreysim into perenapravlennyy Long Jump, then we wake not long time it is located in section stx774, after RET-a we
will leave here:
Means this procedure it makes almost also the very that also Call[.ref]s, with one small difference, that 3 parameter is put
by hand, therefore- that is carried out Jmp and not Call. After this, is caused our procedure restoring RVA, which we already
propatchili. Thus we write further:
_CODEPART3:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;; Restoration of the perenapravlennykh leap;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax, 00401000 ;Begin section .text
_SucheNachLongJumps: ;(_Search LongJump-OB)
cmp byte ptr [eax], E9 ;possibly we deal concerning some Long Jump-OM?
je _JumpGefunden ;(_Jump found)
_SucheNachLongJumpsLoop: ;(_Search LongJumpLoop-OB)
inc eax ;check the following byte
cmp eax, 00782FFF ;We did reach the end?
jne _SucheNachLongJumps ;(_Search LongJumpLoop-OB)
jmp _CODEPART4 ;Restoration perenapravlennykh Call-OB
_JumpGefunden: ;(_Jump found)
mov ecx, dword ptr [eax+01] ;I put dword the value of distance into ecx
add ecx, eax ;I add it with the urgent address
add ecx, 00000005 ;and with the long of leap = the Address- purpose
cmp ecx, 00930000 ;Address- purpose in
jl _SucheNachLongJumpsLoop ;(_Search LongJumpLoop-OB)
cmp ecx, 00933000 ;section stx774?
jnb _SucheNachLongJumpsLoop
push _LongJumpFixReturnPoint ;If yes, to vstavlyau our Return Point
jmp ecx ;and I calculate the correct RVA for our import
_LongJumpFixReturnPoint:
mov ebx, 00933000 ;I put the beginning of our vremmenoy IAT into ebx
_LongJumpFixLoop:
cmp dword ptr [ebx], edx ;and I search for in it our urgent RVA
je _LongJumpFix ;it found, then I jump
add ebx, 00000004 ;if it did not find, I check the following dword
cmp ebx, 00933500 ;we did reach the end?
jl _LongJumpFixLoop ;if no, I make further
jmp eip ;infinite leap, the hand finishing of the errors
_LongJumpFix:
sub ebx, 00933000 ;Puts the symbolic address, izmeryanyy in the beginning IAT in ebx
add ebx, 00783000 ;and future address if vremyanaya IAT was kopirovana into the correct place
_LongJumpIstCallRef: ;(_LongJump-CallRef)
mov word ptr [eax], 15FF ;convert Long Jump in Call [.ref]
mov dword ptr [eax+02], ebx ;with the suitable address of our vremyannoy IAT
jmp _SucheNachLongJumpsLoop ;and I search for the following Long Jump
Fuf, finished with the familiar. Now we can rewrite the old IAT to the new.
:m 00933000 L 500 00783000
All -we are still distant from the game without Saferdisc-a, therefore- that Safedisc-a has 2 new technologies, not to give
to work to our dump. If you wrote in SI, then they must preserve your code:
:!dump \??\C:\nfsu2.patch.dat 00400 500
in order to with the new start of game not to write with its ponovoy, but it is simple to load:
:!loadfile \??\C:\nfsu2.patch.dat 00400500
If the code was written in Hex Editor-e, then this certainly made must not be ;)
4. Restoration internal, perenapravlennykh call
===============================================================
The following explicit attempt Safedisc-a to spoil to us life these are the stifling bytes, which were substituted on THE CC
(instruction int3). If we in SI place
:bpint3
and let us normally neglect game, then after 2 bryakov we will pause at this place:
If we pressing F8 by protreysim instruction Int3, then let us leave into module ntoskrnl. Give to now potreysim the following
Call jumping over rest, so we will reach the end of the procedure:
If we protreysim through IRETD, then let us leave into our "Speed2.exe", truth by two bytes are further, it means before two
following int03 instructions. If we shityu protreysim and through these, we see also the very.
If we leave our bpx by still active, then we will be able to see that if at one place they stand three int3 tyuey podryat,
then after procedure ntoskrnl in the section of .text are placed correct bytes instead of CC. also if we we reach the place
from 4-mya int3, which we already once passed, then correct bytes will be later inscribed into the segment of the code.
For example these bytes:
Certainly to us it is not must so it takes a long time to await, until we pass one and also place two times, but it is simple
to take away in EIP 4. Since we are too lazy in order to to protreysit' entire procedure ntoskrnl, then we will think through
what function API can it is produced copying... Accurately! through Kernel32.WriteProcessMemory.
Give after we they left to OEP let us place breykpoynt on
:bpx writeprocessmemory
Aha, we jingled. If we look to the registers, we will see, that ebx only in which is an address of our speed2.exe. We means
we introduce:
:u ebx
Mda... Unfortunately in the address not the fact that we expected - int3, but "Call 00401089". But all -equal appears
interestingly... give let us introduce
:p ret
in order to to leave function API. Now we see that it was caused Safedisc-om. Give to potreysim procedure without entering
into Call-bi, until we reach this place:
The call of function API "RtlLeaveCriticalSection" shows that procedure it concludes. We means protreysim into the following
Call.
Since the address of stack now in eax- e is contained, then Jmp on EIP jumps there. We see:
It means stack it is corrected and we conclude after RET-a at that place, on which us in general had to derive Call:
Thus we learned, that after the correction of stack and before RET- ohm upper dword in the stack this is the address of the
present purpose Call-a. But therefore- that procedure Safedisc-a such good and with the aid of Kernel32.WriteProcessMemory
copies not correct Call to the correct, then we more should by this be occupied. How we will find other perenapravlennye
Call-bi? The solution will arrive, when we second time jingle on Kernel32.WriteProcessMemory and look on ebx. What we do see?
To XeXe, again "Call 00401089"...
So that we must make:
1. to search the section of .text to the object "Call 00401089"
2. will care that we after the procedure Safedisc-a again would enter into our code.
In the first point it is necessary to focus attention on that, in order to Call-bi as Jmp- y not were static. This means that
we, having Hex values, simply do not read purposeful address, but must its raschityvat'(Adres+5+.dshord ptr from [Adres+5]).
In the second point it is necessary to focus attention on that, in order to the end of the procedure was in the stack. Since
it again is copied, then the code at the end of the procedure, with each call 00401089 is written there on the new. Them it
surely was desirable by this to avoid patch (well fellows this PRAVDA weakly...)
Izza of this we must patchit' still more, when we are found not in the stack into procedures SafeDisc-a. I made this,
although we have other possibilities :)
We write "mov dword ptr [ebp-4], _ReturnPointInternCall;(_ReturPoint Vtutrennego.Call- a)" in the address "6673E11C" and
nopim rest to "Jmp[ebp-4]"
In our "_ ReturnPointInternCall: ;(_ReturPoint Vtutrennego Call-a) "we must, as in procedure SafeDisc-a, to restore stack but
we do not want to leave to the address to which voobshcheto shows Call, but to our further code. It means we should restore
stack on other. But against this on- in more detail. Let us first write down that the fact that we already know:
_CODEPART4:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;; Vostanovleniye perenapravlennykh calls;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax, 00401000
_SucheNachCalls: ;(_Search Call-OB)
cmp byte ptr [eax], E8 ;There can be this Call?
je _CallGefunden
_SucheNachCallsLoop: ;(_Search CallLoop-OB)
inc eax ;check the following byte
cmp eax, 00782FFF ;We did reach ends?
jl _SucheNachCalls ;(_Search Call-OB)
jmp _CODEPART5 ;jump to our last code :)
_CallGefunden: ;(_Call found)
mov ebx, dword ptr [eax+01] ;Gunstock to dlinnu Call-a in ebx
add ebx, eax ;add it with the address
add ebx, 00000005 ;And it is byte with a quantity Call-a
cmp ebx, 00401089 ;this "Call 00401089"?
jne _SucheNachCallsLoop ;(_Search CallLoop-OB)
call eax ;if yes, then I cause and substitute it
jmp _SucheNachCallsLoop ;(_Search CallLoop-OB)
In order to to now have correct value for our stack, it is necessary to potreysit' entire code, until we reach the place
where it is preserved:
Means we pass "push esp, pushfd, pushad" we regard value now in esp. Aha, 0012FF90. Teper6 there is everything that to us
necessarily.
_ReturnPointInternCall: ;(_ReturPoint Vtutrennego Call-a)
mov esp, 0012FF90 ;we want in order to in all registers
popad ;there was also the very that also in the retention
popfd ;when stack stood on 0012FF90.
pop esp
mov esp, 0012FFC0 ;Now we should dispose it so in order to
ret ;in it remained correct address for RETurn-a.
In general "mov esp, 0012FFC0" could be and "add esp, 4" or "add esp 8", this each has Call-a differently. Therefore I
selected reliable version.
Entire vosstanovlenno? It is good, then it is possible to dampit' ". First we make Procdump-om "Full Dump" with all "PE
Rebuilding" opqi4mi, also, WITHOUT the restoration of import. This we still will make. To kt.omu-zhe we will make a dump of
the section.text:
:!dump \??\C:\nfsu2.text.section.fixed.dat 00401000 00382000
5. restoration of stifling it is byte:
=========================================
This time we truth wake to restore stifling bytes. In principle we could for this simple to play a little 24 hours. Although this would deliver to us the heap of the pleasures, not it would be to 100% reliably and it can be we they would note too late some bytes which yet not tyuey vostanovilis'.
As we already learned, all stifling bytes are copied through the the special Exception Handler in ntoskrnl.exe not later than with the second call.As there would be always best anything if we obishchem the section of .text to object int3s, let us then carry out them in order to to rewrite to the correct bytes and it is reverted to our code... And here we encounter problemmoy. We truth do want to propatchit' WindowsNT Kernel??? To definitely net(pochti would tear my OS... of:.Kh) and that before this? Mmmmm... before this the section of .text. Surely we will not be able to go around it by us destruction. Therefore we made a dump.
My first idea was, after each int3 or after each block int3 write down C3(instrukqi4 RET) and cause it. But then we again encounter problemmoy. In our stifling bytes can prove to be pryzhki(kak we they memorized in our first example). Second problemma was, to rewrite everything except Int3s bytes C3. means even after leap we let us prove to be on RET-e... But also in this idea est6 the difficulty:
We indeed must somehow verify, this stifling byte or is simple the byte of another instruction. In order to better to understand that I have in the form, you must with the command of softaysa
s 00401000 l ffffffff cc cc
to search the section of..tekht. You will note that in other functions sufficiently much the CC it is byte. For example:
If we wander a little into the bottom or upward, we will see the present function:
If we try, nevertheless to neglect these Int3s, then Exception Handler does not copy these bytes, but simply is opened NT Exception Dispatcher. Appears MessageBox, that there was Exception and game is shut.
Also with the search of the section of .text we wake to frequently encounter with this:
Here we deal concerning the special case, in which are always encountered NOP and 5 int3s confronting RET-om. If we will carry out these Int3s, that they to be adopted by the special Exception handler-om and it will rewrite them to 9090909090. Why the special case? Well, this we will see when let us try to carry out the following Int3s, about which we know that this stifling bytes. They not will be rewritten. This seems by a good motion from side Macrovision. These bytes NEVER are carried out with the normal circumstances, therefore- that they are encountered only after podprotsedur and before them always stands RET. Means if we them we will carry out, that is sewn it learns about the fact that we we want it to break and us more it will help in no way...
Why I do write that it does seem? To khekhe, since we about this know, we simply will search entire section of .text to the object of chain it is byte "C3 CC CC CC CC CC 90" and zanopim it. To us there remains only to solve problem with the fact, as we learn that obtained Int3s stifling bytes. It is necessary not much to look for this, since we should find as much as possible present stifling it is byte in order to to note similarity.
We first note, that all present stifling bytes not shorter than two it is byte, in addition to this before the present stifling bytes frequently stands Call[ref], truth not always. But if we look well that let us see, that is a little above the stifling byte it stands similar Call[ref]. The very great distance which I saw between the first Int3 block to FF beginning Call[ref]s, were 2C byte. Pravda it surely changes with each game and version.
It means our plan it is such:
We will search the section of .text to the object OF THE CC it is byte and FF15 words. However, potential Call[ref].s must be still checked, they do read our IAT. Everything except our Int3s and checked Call[ref].s will be rewritten by instruction C3. Now we sdampim the section of .text After this, we will carry out everything Int3s, which have the maximum distance of -2C to Call[ref] and by sdampim again when everything will be restored. Now we can compare both files with any Patchengine as, for instance, Code Fusion and write down changes in our above sdamplennuyu section of .text.
If we began all this to write, that we would stumble on two problemmy. I immediately will describe about them, in order to to free us from not the necessary work:
1. Problemma with three int3s
2. Problemma with seven int3s
Restoration of several, the first stifling bytes it functions excellently. However, first problemma appears sufficiently rapidly and only when are carried out three int3. Therefore- that some Int3s of these triple blocks this "add esp, XX"(kotorye have a length into three bytes). Since they after record are carried out in the segment, that RETurn the address of stack correct and with by following RET-e we end in nervane. We means they must before we let us carry out any Int3, to place after all triple blocks Int3- eating leap to the stack- correcting procedure.
Second problemma appears at the end of the section of .text. To nekotory.e Int3 blocks this "mov dword ptr [esi], XX". Surely some they will ask "A in what strictly of problemma? Well, give then let us look on esi. At it the value lies 00000000, which is not correct address for the retention, for which our game does not have right of record. Result - termination... Now we can enter in the beginning of our Int3- reducing procedure of 00933000 (adres Safedisc Loader Section) in esi.
Everything is understandable? Then we write down:
_CODEPART5:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;; restoration of stifling it is byte ;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov esi, 00933000 ;Soot address with the rights of record in esi
mov eax, 00401000 ;Begin section .text
_SucheNachInt3sUndCallRefs: ;(_Search Int3 and CallRefs)
cmp byte ptr [eax], CC ;Urgent function this Int3?
je _Int3Gefunden ;(_found Int3)
cmp word ptr [eax], 15FF ;or Call [.ref]?
je _CODEPART5CallRefGefunden ;(_CODEPART5 found CallRef)
_UeberschreibeByte: ;(_copy the bytes)
mov byte ptr [eax], C3 ;If no that it copies them
inc eax ;and I make further with the following byte
cmp eax, 00782FFF ;We are ready?
jl _SucheNachInt3sUndCallRefs ;(_Search Int3 and CallRefs)
jmp _SucheNach3erBlockInt3s: ;(_Search For the block Int3-e in Three bytes)
_Int3Gefunden: ;(_found Int3)
cmp word ptr [eax+04], 90CC ;We deal concerning the trick from Macrovision ?
je _MacrovisionTrickGefunden ;(_found Trick From Macrovision)
inc eax ;In other case urgent byte copies and it makes further
jmp _SucheNachInt3sUndCallRefs ;(_Search Int3 and CallRefs)
_MacrovisionTrickGefunden: ;(_found Trick From Macrovision)
mov dword ptr [eax], 90909090 ;nopit trick from Macrovision
mov byte ptr [eax+04], 90
add eax, 00000006 ;check the following function
jmp _SucheNachInt3sUndCallRefs ;(_Search Int3 and CallRefs)
_CODEPART5CallRefGefunden: ;(_CODEPART5 found CallRef)
cmp dword ptr [eax+02], 00783000 ;read our potential Call[ref]
jl _UeberschreibeByte ;(_copy the bytes)
cmp dword ptr [eax+02], 00784000 ;address from our IAT?
ja _UeberschreibeByte ;(_copy the bytes) ;if no, that copies it
add eax, 00000006 ;in other case I leave by its free
jmp _SucheNachInt3sUndCallRefs
_SucheNach3erBlockInt3s: ;(_Search For the block Int3-e in Three bytes)
mov eax, 00401000 ;Begin section .text
_SucheNach3erBlockInt3sLoop: ;(_Search For the block Int3 Loop-ob in Three bytes)
cmp word ptr [eax], CCCC ;two are located on the urgent address Int3-a?
je _2Int3sGefunden
_NaechstesInt3: ;(_Following Int3)
inc eax ;In other case I increase the address
cmp eax, 00782FFF ;End?
jl _SucheNach3erBlockInt3sLoop ;(_Search For the block Int3 Loop-ob in Three bytes)
jmp eip ;Eternal cycle, now we should sdampit' the section.text
;(nfsu2.stolen.bytes.not.recovered.dat)
jmp _SucheNachInt3s ;(_Search Int3-eb) ;and to continue with the last part :)
_2Int3sGefunden: ;(_Two are found Int3)
cmp byte ptr [eax+02], CC ;Third byte also Int3?
jne _NaechstesInt3 ;(_Following Int3) ;If no, search for further.
cmp byte ptr [eax+03], C3 ;This the latter or afterward be still
jne _NaechstesInt3 ;(_Following Int3) ;If not latter, search for further
cmp byte ptr [eax-01], CC ;Is there before that checked still Int3-and?
je _NaechstesInt3 ;(_Following Int3) ;If yes, search for further
add eax, 00000003 ;Soot address afterward Int3-a in eax.
mov ebx, eax ;Soot the value eax-a in ebx
add ebx, 00000005 ;To this I add the length Long Jump-a
sub ebx, _CorrectStack ;and I take away the address of the purpose
imul ebx, FFFFFFFF ;We want to jump back, it means we should this all multiply on (-1)
mov byte ptr [eax], E9 ;I write instruction for Long Jump-a
mov dword ptr [eax+01], ebx ;and the suitable length Jump-a
jmp _NaechstesInt3 ;(_Following Int3)
_CorrectStack:
cmp word ptr [eax], C483 ;3 stifling bytes were "add esp, XX"
jne _MussNichtKorrigiertWerden ;(_It Must not Be Restored)
movzx ebx, byte ptr [eax+02] ;I write "XX" in ebx
sub esp, ebx ;and I take away this value from the stack
_MussNichtKorrigiertWerden: ;(_It Must not Be Restored)
ret ;return back
_SucheNachInt3s: ; (_Search Int3-eb)
mov eax, 00401000 ;Begin section .text
_SucheNachInt3sLoop: ;(_Search Int3 Loop-ob)
cmp word ptr [eax], CCCC ;can be to aktual'ny.e two bytes stifling
je _TesteInt3 ;(_check Int3) ;if yes, check them
inc eax ;in other case I check the following
cmp eax, 00782FFF ;We reached the end of the section .text?
jl _SucheNachInt3sLoop: ;(_Search Int3Loop-ob)
jmp eip ;the bezkonechnyy cycle, We COULD Make This!!!
_TesteInt3: ;(_check Int3)
mov ebx, eax ;write the value eax-a in ebx
sub ebx, 0000002C ;and I take away away from this the maximum permissible distance to Call[.ref]-y
_TesteInt3Loop: ;(_check Int3 Loop)
cmp word ptr [ebx], 15FF ;There is whether any Call[.ref] in the urgent distance to Int3
je _CalleInt3 ;(_cause Int3)
inc ebx ;If no, I decrease the distance
cmp ebx, eax ;We verified entire maximum permissible distance?
jne _TesteInt3Loop ;(_check Int3 Loop) ;If no, to the ides further
add eax, 00000002 ;In other case I do not carry out urgent Int3
jmp _SucheNachInt3sLoop ;(_Search Int3Loop-ob) ;and I search for further
_CalleInt3: ;(_cause Int3)
pushad ;preserve all registers
pushfd ;and the stack.
call eax ;cause address Int3-a, in order to restore the stifling byte
popfd ;restore the stack
popad ;and all registers
cmp word ptr [eax], CCCC ;Stifling bytes were restored
je _CalleInt3 ;(_cause Int3) ;If no, cause them again
add eax, 00000002 ;In other case I search for the following
jmp _SucheNachInt3sLoop ;(_Search Int3Loop-ob)
Fuf... here almost and everything. With the fulfillment of procedure we should just in case place Breakpoint on NT Exception Dispatcher, which is called when we we attempt to restore stifling bytes which them in reality they are not.
:bpx KiUserExceptionDispatcher
Opa, we see what, if we neglect our code, we sometimes will jingle on KiUserExceptionDispatcher. If we now introduce
:u eax
that we will see that on our criteria these bytes they must be stifling. Somewhat higher Int3-ob is Call that leading to Kernel32.CreateMutexA. The matter in the fact that after some address of stifling it is byte more no. In NFSU2 this approximately 00730000. It means everything restored. In softayse to us there remained only to sdampit' section.
:!dump \??\C:\nfsu2.stolen.bytes.recovered.dat 00401000 00382000
Now we can shut softays. Instead of this we will open Code Fusion and will create new project. In the line "Patched File:" we will point out "Any File" after harvesting to the sootvesvuyushchuyu button. With "Data to patch" we will select "File Compare" and by attitude of tuning as ukazanno below:
As original file we will point out our section of .text, which was sdamplena after perepisaniya bytes C3. As propatchenyy file we will point out our section of .text, in which we restored stifling bytes. We will remove jackdaw with "Save Original Data in project". So we will attain that in order to we could renew section .rdata(improt/vnutrenniye Call-bi) with that created patchem.
Means if we we press on "Compare", that we will obtain the list of differences, with which we now can create patch "Int3fix".
This ekseshnik we to srazu-zhe to vyzovim and will point out our restored section of .text as Target File (nfsu2.text.section.fixed.dat). After file we renewed we can s grow prettier conscience name it "nfsu2.text.section.fully.fixed.dat" :)
6. Recompilation
===============================
Now we will open our Full Dump made somewhat higher in Hex Worshop- e, let us leave for address 1000,
vyb.er.em Edit = Select Block and let us point out as value "00381821"(.Raw Size of the section of .text).
Now we can harvest Del(.entf) in order to to remove entire section.
Now give let us open our "nfsu2.text.section.fully.fixed.dat" in the same Hex by Workshop- e, vydilim in it also 00381821 it is byte, we copy them and will put into the address 1000 Full Dump- A
To ktomu-zhe we can the latter 7000h ba1tov(kogda- that those belonging to both sections Safedisc- A) simply remove all this preserve.
From PEditor- ohms we will move away from Header- A still and last two sections, which we already removed from the file.
Stoyte, we seems something they forgot to make...Accurately, we yet not perekompilirovali import.
In order to to make this, we should again open Speed2.exe, is jingled on OEP and to neglect our patch for the import (only not for the stifling it is byte;.D...) and in conclusion to rewrite the old IAT to the new.
Now we should open Imprec, select Speed2 in the list of active processes, introduce OEP and harvest on "IAT autosearch". After this, on "Fix Dump" and to select our dump... IT IS PREPARED!!!
To us there remained only to perekompilirovat' our exe with LordPE, PEditor- ohm or PE Rebuilder- ohm.
7. Conclusion
=========================================
Thus, long tutorial approaches toward the end. I hope to you it was
pleased to read and you learned to something.
Gr6@4.e an (no particular Order): das gesamte CIP Team
(ZeroJump.BigDragon, *.RemedY *),old genius r!.sc, Peex, quake_.qer und
alle anderen aus dem Chan, mein Soldier Girl & meine Vatos, und last
but not least an DICH
kEEP iT uP...
mAGiC...