Documente Academic
Documente Profesional
Documente Cultură
Forewords
Into this Tutorial
1.
The target
2.
3.
4.
nicely implemented and nice to describe into a tutorial. This time is the turn of
have been useful to reverse and document in a tutorial, mostly because I used
a lot a combination of OllyDbg and IDA Debugger.
This time I preferred using IDA as much as possible to understand the code and
then OllyDbg only to verify the assumptions done. This method of investigation is
usually very common when you have to analyze malware, but also very handy,
because IDA allows saving of reversing sessions, code editing, name changing
and so on.
5.
I need reversing instruments that could be frozen at any time (I have very few
6.
and scattered spare time): I usually run the dynamic sessions with OllyDbg on a
7.
IDA (which can also be closed and started again later for another session).
8.
I will end this journey doing a complete keygen of the program, showing the
9.
Conclusions
VMWARE virtual PC which I can freeze at anytime and the analysis sessions with
process you can use too with other programs and will include in the distribution
its sources (simple C).
As usual there are cracks and keygens too for this program around the net and
this tutorial will not create many troubles than those already created by
someone else before me.
Moreover it will then be the occasion to deeper dig the IDA functionalities in
combination with OllyDbg, I will try to be as much clear as possible, for
everyone.
Have phun,
Shub
Author: Shub-Nigurrath
PAGE 2
Disclaimers
All code included with this tutorial is free to use and modify; we only ask that you mention where you found it. This
tutorial is also free to distribute in its current unaltered form, with all the included supplements.
All the commercial programs used within this document have been used only for the purpose of demonstrating
the theories and methods described. No distribution of patched applications has been done under any media or
host. The applications used were most of the times already been patched, and cracked versions were available
since a lot of time. ARTeam or the authors of the paper cannot be considered responsible for damages to the
companies holding rights on those programs. The scope of this tutorial as well as any other ARTeam tutorial is of
sharing knowledge and teaching how to patch applications, how to bypass protections and generally speaking
how to improve the RCE art and generally the comprehension of what happens under the hood. We are not
releasing any cracked application. We are what we know..
Verification
ARTeam.esfv can be opened in the ARTeamESFVChecker to verify all files have been released by ARTeam and
are unaltered. The ARTeamESFVChecker can be obtained in the release section of the ARTeam site:
http://releases.accessroot.com
Table of Contents
1.
2.
3.
4.
5.
6.
7.
PAGE 3
Of course the first thing is as usual to install the application and see if and how its components are protected. You
can find in the installation directory these executables:
Control.exe
SbieDll.dll
SbieDrv.sys
Start.exe
There are other executables of course but their names identify them clearly as auxiliary programs, moreover they
do not have any graphic resource inside (no dialog, no strings etc).
For all of them the PEiD reports:
Good, it seems at all a simple target, a target for which a tutorial shouldnt be needed..or not?
PAGE 4
A)
B)
D)
C)
E)
F)
PAGE 5
push
call
1
sub_1002580
If you go looking at the sub_1002580 you will see that its calling NtTerminateProcess and that the argument
pushed on stack is passed to it as exit code. IDA identified the local argument for you marking it as arg_0 and
interestingly if you highlight it with the mouse it also highlights each usage of that name in the following code.
.text:010025AD
.text:010025B0
.text:010025B1
.text:010025B3
mov
push
push
call
eax, [ebp+arg_0]
eax
0FFFFFFFFh
ds:NtTerminateProcess
PAGE 6
We can then rename the function sub_1002580 into a more meaningful TerminateStart.
The function start.exe call just before the function CheckStatus call two other functions:
One is the function sub_1002FB0, which is interesting because launches the program control.exe as in Figure 5.
PAGE 7
The second call is at loc_1003A25 where the sub_10038E0 retrieves the parameters from the start.exe
command-line and launches the program given to start through its command-line, using ShellExecuteExW.
Interestingly IDA also recognize the SHELLEXECUTEINFO elements of the call, you can see the following in IDA. The
code starting at loc_1003908 stores the command-line into the buffer Dest. This buffer will be used later.
mov
mov
If you follow the variables hToken and Token you will find that are
respectively crated by a call to CreateProcessAsUserW and a call to
SetThreadToken. Dest is instead the process being sandboxed.
This function returns its result in eax (as usual for the functions return values compiled from C), eax (actually ax
only) is then moved to var_414, var_414 is immediately checked against 0. If its equal to 0 the function
SbieDll_InitProcess() is called.
PAGE 8
0h
0C0000021h
ok, no errors, moves al=1 and no other calls. So not a good value but not a limitation
itself
0C0000268h
you have been using sandboxie for more than 30 days..
0C0000268h=UNREG_30DAYSLIMIT
0C0000259h
The unregistered version doesn't support more than one sandboxie...
0C0000259h=UNREG_MORESANDBOXIE
We must understand what the function SbieApi_StartProcess does and generally what all the functions of the dll
SbieDll.dll do.
mov
eax, [ebp-5Ch]
call
mov
cmp
sub_7D23ABA0
[ebp-5Ch], eax
dword ptr [ebp-5Ch], 0
PAGE 9
PAGE 10
The call sub_7D23ABA0 is a simple function that initializes a driver called \\Device\\SandboxieDriverApi, if not
already initialized.
At location 7D23ABA6 theres a compare that calls NtOpenFile using the above string (actually opens the driver
SandboxieDriverApi).
.text:7D23ABA6
cmp
drvFileHandle, 0FFFFFFFFh
If drvFileHandle is already opened (!=-1) the function just calls NtDeviceIoControlFile, which is an API that
sends requests to the driver:
The NtDeviceIoControlFile service is a devicedependent interface that extends the control that
applications have over various devices within the
system. This application programming interface (API)
provides a consistent view of the input and output
data to the system while still providing the
application and the driver a device-dependent
method of specifying a communications interface
(see Figure 7).
Even if documentation tells that its a deprecated
function is still used by windows as kernel level and
might be used. What is important among the
parameters is the IoControlCode:
Code that indicates which device I/O control
function is to be executed.
The IoControlCode used is always 222007h in the SbieDll dll.
PAGE 11
We can then rename this call to a more meaningful name, I used SbieDrv_222007h, just to be able to find it
immediately.
What is needed is to understand what are the other values passed to the API. To
do this we will use our beloved OllyDbg.
Open start.exe into OllyDbg and place a breakpoint at 7D23AC40 (call
ds:NtDeviceIoControlFile) into the SbieDll.dll
What you will see is that the InputBuffer local variable is apparently the only way
the driver has to communicate back the results of the call.
0006F8E0
0006F8E4
0006F8E8
0006F8EC
0006F914
00222007
0006F970
00000040
|Arg5
|Arg6
|Arg7
|Arg8
=
=
=
=
0006F914
00222007
0006F970
00000040
IoStatusBlock
IoControCode
InputBuffer
InputBufferLength
push
call
mov
mov
edx
SbieDrv_222007h
[ebp-48h], eax
eax, [ebp-48h]
Looking at SbieDrv_222007h it is evident that the eax value is actually the NTSTATUSReturn
.text:7D23AC49
mov
eax, [ebp+NTSTATUSReturn]
PAGE 12
Finally to conclude this trip into the dll we need to fix two left concepts:
1. We landed here looking for the code of the API SbieApi_StartProcess so we need to jump back
looking for the caller, how the parameter InputBuffer is created.
2. Do all the other APIs work like this?
The value of edx points to the value 12340006 which is pushed at 7D23B13F on the stack.
.text:7D23B13F
mov
PAGE 13
mov [ecx+18], esi <---- pRip->IoStatus.Status (this is same code that returns from Dispatch routines)
I found an implementation of IoCompleteRequest here: http://www.reactos.org/pipermail/ros-diffs/2006June/012842.html
2
PAGE 14
This will bring you right to dispatch routines in the driver, all the times. For example for this specific driver this part of
code is located at loc_230AA, see Figure 9.
PAGE 15
What we obtain is then a more simple view of the DispatchMessage() routine, see Figure 12. Figure 12 also shows
that the table unk_2200 is read into memory only the first time when the driver doesnt find it: the driver goes into
error mode calling KeBugCheckEx, otherwise the driver normally handle the request calling IoCompleteRequest.
The call to BugCheckEx is important:
When a driver goes into error mode the KeBugCheckEx
mode is the last resort the driver can take to adjust its status
and avoid wild BSODs. The KeBugCheckEx routine brings
down the system in a controlled manner when the caller
discovers an unrecoverable inconsistency that would
corrupt the system if the caller continued to run.
The function is called when the pointers contained into
unk_2200 are not loaded in memory; the driver sets a BSOD
(Blue Screen of Death) reporting some useful information.
PAGE 16
We are not successfully reversed the structure of the DispatchMessage and the meaning of unk_2200 table of
functions.
PAGE 17
The unk_2200 table of functions is actually a table of the services offered by the driver, the functions are called
using the value InputBuffer passed as argument to the NtDeviceIoControlFile; the offset of the table is got
subtracting the value 12340000h to InputBuffer.
For example then:
1.
The
constant
12340001h is
used in
the
SbieApi_GetVersion
2. The first position of the unk_22000 table is the
function sub_11240
3. We can rename it as HGetVersion. This is the
handler of the service 12340001h
The same can be done with all the other function pointers
starting from unk_22000. We can rename this location
pressing N over it with IDA and call it Services_Table.
db
6
db
0
db 34h ; 4
db 12h
dd offset sub_1E790
The element at 0x00022030 is the number of the handler minus the offset 12340000h.
We now have all the elements to correctly track down the events of the program through the SbieDll APIs.
The most relevant handlers are the following ones (with the final name given in IDA):
SbieApi_StartProcess
SbieApi_SetLicense
SbieApi_SetUserName
SbieApi_GetLicense
SbieApi_QueryConf
12340005h
12340006h
12340015h
12340004h
1234000Fh
5h
6h
15h
04h
0Fh
sub_1E790
sub_1CA50
sub_132D0
sub_1C9F0
sub_13080
HStartProcess
HSetLicence
HSetUserName
HGetLicense
HQueryConf
db
dd
dd
dd
dd
dd
dd
dd
dd
dd
dd
dd
dd
dd
dd
1
offset
offset
offset
offset
offset
offset
offset
offset
offset
offset
offset
offset
offset
offset
HGetVersion
; handle 12340001
HGetWork
HLog
HCallZero
HGetLicense
HSetLicence
HStartProcess
HQueryProcess
HQueryBoxPath
HQuerProcessPath
HQueryPathList
HEnumProcess
HDisableForceProcess
HGetInjectSaveArea
dd
dd
dd
dd
dd
dd
dd
dd
dd
offset
offset
offset
offset
offset
offset
offset
offset
offset
PAGE 18
HGetSetDeviceMap
HRenameFile
HUsedInternally_to_driver
HCreateDirOrLink
HDuplicateObject
HHookTramp
HReloadConf
HQueryConf
HSetUserName
PAGE 19
Looking at Figure 13 we can say that for the UNREG_30DAYSLIMIT we must fix the call sub_1CB40 because this
function is called several times around the code. According to code above if al=0 then UNREG_30DAYSLIMIT is
set. So sub_1CB40 must return al!=0 always.
If you look at the code of the function sub_1CB40, there's only one place where al is set to 0
.text:0001CB85
jz
short loc_1CB8F ; this one becomes a JMP
.text:0001CB80 loc_1CB80:
; CODE XREF: sub_1CB40+36j
.text:0001CB80
mov
al, [ebp+arg_0]
.text:0001CB83
test
al, al
.text:0001CB85
jz
short loc_1CB8F
.text:0001CB87
xor
al, al
.text:0001CB89
mov
esp, ebp
.text:0001CB8B
pop
ebp
.text:0001CB8C
retn
4
.text:0001CB8F ; -------------------------------------------------------------------------.text:0001CB8F
.text:0001CB8F loc_1CB8F:
; CODE XREF: sub_1CB40+45j
so the patch1 on the driver is: 0001CB85 JZ becomes a JMP
PAGE 20
The other limitation, connected to UNREG_MORESANDBOXIE has a similar structure, but involves the function
sub_1E6D0, which must return al!=0 as well to be good for us.
only
called
in
mov
al, [ebp+var_1]
mov
[ebp+var_1], 0
PAGE 21
So to have this call to return a value correctly (no badboys) we have to push a value of 0 as argument.
Interestingly the call references to sub_1CB40 are these:
p sub_1E240+8
call
p sub_1E6D0+6
call
p HStartProcess+31 call
sub_1CB40
sub_1CB40
sub_1CB40
The first two gives to the function a value of 1, like for example:
.text:0001E246
.text:0001E248
push
call
1
sub_1CB40
The third one instead is inside HStartProcess, the detail of this third one is the following:
.text:0001E7C0 loc_1E7C0:
.text:0001E7C0
push
ebx
.text:0001E7C1
call
sub_1CB40
the value of ebx is pushed to the function and few lines
above it is xored in this line:
.text:0001E79A
xor
ebx, ebx
mov ebx, 1 or better to save space a mov bl,1 (B3 01) which fits into the available
push
push
call
ecx
edi
ds:_wcsicmp
; wchar_t *
; wchar_t *
Looks very promising for another patch: the insertion of a call to DbgPrint3 in order to fish the real serial over a
Dbgmessage...I will leave this for you
PAGE 22
The result of this modification is not only a successful registration check, but also the removal of all the other
limitations we saw at the beginning of this document, see Figure 17.
PAGE 23
What the function SbiApi_GetLicense does is to call the driver passing a buffer, it writes 0 at the first byte if the
program is not registered.
The SbieApi_GetLicense is reported in Figure 18. The portion of code circled is the one responsible of zeroing
out the first byte of the argument on the stack, specifically the second mov. This portion of code is executed only
when eax<0, so to have a good result we must force HGetLicence on the driver to return eax>=0.
PAGE 24
Figure 18 - SbieApi_GetLicense
Figure 19 reports the disassembly view of HGetLicense. Into this function as you can see there are two possible
paths: the correct one, on the right, ends with a xor eax, eax which is what we needed to recognize it. So the
patch this time forces the execution of this branch:
Patch
.text:0001C9FA jnz
short loc_1CA01
PAGE 25
Figure 19 - HGetLicense
This last modification allows to nicely seeing our name in the about box:
PAGE 26
The PE files headers include a CheckSum field which is located into the:
IMAGE_NT_HEADER IMAGE_OPTIONAL_HEADER CheckSum
This value is an overall checksum of the whole file, often not set and left to 0x0000 by most compilers and thus
doesn't happens often to worry about it, but sometimes this value is used to check if there have been alterations
in the executable file. There is for example an API, MapFileAndCheckSum(), which calculates the real checksum
of a PE file and reports also the value stored into the PE Header. It is then simple for simple protectors to detect
alterations of a PE file, even of a single byte.
It's a simple technique that advanced protector doesn't use too often and you can of course intercept this API
and modify it online or skip its call, but for example with PocketPC smartphones or system drivers this check is
done by the operative system, so you simply have no choice to intercept this check and the only way is to fix the
value stored in the PE file header. The system uses this value to check the integrity of a driver, before loading it. If
you patch a driver and simply load it the result is that it will not be loaded by the system because the stored
checksum and the calculated one are different.
PAGE 27
PAGE 28
I properly commented all the parts of the code, it should be clear that the sub_1C320 is the routine that
calculates the serial number, which is then compared with the serial given by the user through a _wcsicmp, that is
a wide char (Unicode) comparison of strings not case sensitive. We can then rename the sub_1C320 with
SerialCalculation.
If you go into the SerialCalculation you can see that IDA
identified two arguments for the function, called arg_0 and arg_4.
These two arguments are passed through the activation record
mechanism typical of any call with the Intel platforms. Depending on
the calling convention used by the compiler/language (the
possibilities are VisualC++ and C in general or Borland and Pascal)
the arguments are pushed on the stack in different order. I know
here, thanks to PEiD, that the driver was compiled using VisualC++
then I used the C parameter pushing convention to restore the
prototype of the SerialCalculation routine. The result is:
SerialCalculation(UCHAR *name, UCHAR *serial);
Assembler
Stack
C Calling Convention
push Argn
..
push Arg2
push Arg1
call dummy
Arg1
Arg2
Argn
Argn
...
Arg2
Arg1
PAGE 29
The most interesting part of the function is shown in Figure 23, where we understand that the serial is actually
calculated using a string of valid characters (off_223F0), that it is stored in the variable arg_4 and that it is long 0Eh
characters (an Unicode string of 6 characters, that is what we experience using Sandboxie).
External Dependencies
(constants, global variables)
Parameters
Function
Function
Results
Function
Called Functions
Figure 24 - General schema of a Function to test Atomicity
PAGE 30
Figure 24 reports the structure of a general function where, beside the normal flow of Parameters and Results,
there are two side flows of information: the Called Functions and the External Dependencies (constants or global
variables). These flows can also be bi-directional depending on the possibility of the Function to read and
eventually write some values. In order to create a keygen you must understand and document all these flows,
once isolated the function responsible of the serial number calculation. The keygen must re-create into a
separated program the same environment the Function wants, otherwise it will not work4
This property allows taking the function as it is, in assembler, and extracting it from the rest of the program, without
too much problems. A first overview of the function reveals that this function is atomic, but we will verify it also to
show the method for more complex cases and for the drivers specifically.
Easy tests in IDA reports that the function SerialCalculation doesnt call any other function and depend only from
the external constant at off_223F0. We anyway need to test if it can live on its own, with the proper arguments!!
Usually OllyDbg is very handy when you have to verify the atomicity of a function, but we are now reversing a
driver, which cannot be loaded into a Ring3 debugger. What we need is to properly modify the driver so as
OllyDbg will be able to load it (see also [8]), even if not completely execute it.
The method simply changes the *.sys PE Header so as to transform the driver into a normal Dll or a normal
executable: remember that a driver is a native executable or dll, linked to native dlls (usually hal.dll and
ntoskrnl.exe). We will use CFF Explorer to change the driver:
1.
2.
3.
Change the Data Directories Import Directory RVA and Import Directory Size to 0, to erase the import
tables of system dlls
If this operation is too complex or long you can always create an Oraculum or self-keygen [6, 7]
PAGE 31
Now your driver is ready for OllyDbg, of course it will not work, but we can open into OllyDbg and work it out for
our needs.
.
.
.
50
56
E8 6DF8FFFF
PUSH EAX
PUSH ESI
CALL SbieDrv.003BC320
The result is that we skip all the rest of the code and will go
simulating the driver execution, when it calls the SerialCalculation
routine.
Using IDA we supposed which are the meanings of EAX and ESI and we can then now modify them so as to point
somewhere in memory, useful for our test.
These are the steps I will cover now, being the first already done:
1.
2.
50
PUSH EAX
Generally speaking jumping the execution point wheres the call of the function that will generate the
serial number, is a good trick. This allows skipping all the rest of the program and allows us to test the
input conditions to the function so as to prepare for the keygen we are going to build. Its like in a
surgical operation where we want to transplant a living organ from the program to the keygen
3.
find a good place where to let them point, look for the memory map and find a place with all 0000 ... for
example I used:
EAX=3C2440 where there's space for the new string with the serial
ESI=3C2420 where I wrote in Unicode format "Shub-Nigurrath"
4.
change EAX and ESI so as to point respectively to the name in Unicode and to a position where to store
the serial number.
5.
PAGE 32
E8 6DF8FFFF
CALL SbieDrv.003BC320
You can see that the function properly filled the buffer pointed by ESI with a serial number.
003C2420
003C2430
003C2440
53 00 68 00 75 00 62 00 2D 00 4E 00 69 00 67 00
75 00 72 00 72 00 61 00 74 00 68 00 00 00 00 00
42 00 47 00 4E 00 4B 00 52 00 41 00 31 00 00 00
S.h.u.b.-.N.i.g.
u.r.r.a.t.h.....
B.G.N.K.R.A.1...
6.
The function SerialCalculation is easily Atomic and can be extracted from the driver!
PAGE 33
Remove the trailing addresses, leaving only the assembler instructions (remove all those things like
.text:0001C320). The format of the assembler instructions shown by IDA is the same supported by the
C language by means fo the __asm instruction. This is very handy, because you can copy and paste
quite effortlessly the code from IDA to a C program.
Change the relative addresses of the parameters and local variables of the function. The local variables
are not anymore referenced as offset of the EBP register but directly
So for example into IDA there's these lines:
mov
mov
edi, [ebp+arg_0]
[ebp+var_4], edx
edi, [arg_0]
[var_4], edx
The offset with ebp is correctly handled by the compiler and I don't need it anymore
2.
Insert the assembler into an __asm{} block and then into a naked function (see [9] for an explanation of
what are the naked functions).
Using the naked functions allows skipping the prolog and epilog instructions the compiler places to
correctly handle the calls and the stack. This operation was already been done by the compiler that
created the call we are taking out from the driver. So our keygenerator doesnt need to add them
anymore. We will leave the prolog and epilog that are already between the asm instructions of the
SerialCalculation, without even worrying of which precisely are these instructions..
3.
Add all the external constants and the local variables used by SerialCalculation just outside the
function (the naked functions cannot have such variables into its body):
//string referenced into the program
char aA1b2c3d4e5f6g7[]="A1B2C3D4E5F6G7H8V9JKLMNPQRSTWXYZ";
//simulates the offset call we saw in IDA, through a pointer holding the start
//of the string..
char* off_223F0=aA1b2c3d4e5f6g7;
//local variables IDA identified for us and we placed them back, the routine use them
DWORD var_4=0, var_8=0;
4.
Assemble everything using UNICODE format strings; we saw that the arguments of the
SerialCalculation function are Unicode strings. Instead of printf use the widechar version
wprintf/wscanf or alternatively the printf/scanf with the correct format specifier.
A note: you could also use printf but you must correctly handle the Unicode string. For example:
wchar_t wstring=LExaxmple of string;
wprintf (LI am an Unicode text, shown on not Unicode screen %s, wstring).
printf(I am an Unicode text shown on not Unicode screen %S,wstring);
in this example the Unicode constant shown (I am an Unicode) is not really important, the important
is to show it on screen; the Unicode string wstring is shown correctly using wprint or the printf with %S
format specifier. The same happens with wscanf and scanf.
PAGE 34
PAGE 35
loc_1C35E:
; CODE XREF: SerialCalculation+3A_j
test
al, 2
mov
byte ptr [var_4], cl
jz
short loc_1C376
mov
edx, [var_4]
mov
cl, al
shl
cl, 1
shr
edx, 8
add
dl, cl
mov
byte ptr [var_4+1], dl
jmp
short loc_1C37A
; --------------------------------------------------------------------------loc_1C376:
add
byte ptr [var_4+1], 2
loc_1C37A:
; CODE XREF: SerialCalculation+54_j
test
al, 4
mov
cl, byte ptr [var_4+2]
jz
short loc_1C38A
mov
dl, al
shl
dl, 2
add
cl, dl
jmp
short loc_1C38D
; --------------------------------------------------------------------------loc_1C38A:
add
cl, 4
loc_1C38D:
; CODE XREF: SerialCalculation+68_j
test
al, 8
mov
byte ptr [var_4+2], cl
jz
short loc_1C3A3
mov
dl, byte ptr [var_4+3]
mov
cl, al
shl
cl, 3
add
dl, cl
mov
byte ptr [var_4+3], dl
jmp
short loc_1C3A7
; --------------------------------------------------------------------------loc_1C3A3:
add
byte ptr [var_4+3], 8
loc_1C3A7:
; CODE XREF: SerialCalculation+81_j
test
al, 10h
mov
cl, byte ptr [var_4]
jz
short loc_1C3B7
mov
dl, al
shl
dl, 4
add
cl, dl
jmp
short loc_1C3BA
; --------------------------------------------------------------------------loc_1C3B7:
add
cl, 10h
loc_1C3BA:
test
al, 20h
mov
byte ptr [var_4], cl
jz
short loc_1C3D0
mov
dl, byte ptr [var_4+1]
mov
cl, al
shl
cl, 5
add
dl, cl
mov
byte ptr [var_4+1], dl
PAGE 36
jmp
short loc_1C3D4
; --------------------------------------------------------------------------loc_1C3D0:
add
byte ptr [var_4+1], 20h
loc_1C3D4:
; CODE XREF: SerialCalculation+AE_j
test
al, 40h
mov
cl, byte ptr [var_4+2]
jz
short loc_1C3E4
mov
dl, al
shl
dl, 6
add
cl, dl
jmp
short loc_1C3E7
; --------------------------------------------------------------------------loc_1C3E4:
add
cl, 40h
loc_1C3E7:
; CODE XREF: SerialCalculation+C2_j
test
al, al
mov
byte ptr [var_4+2], cl
jns
short loc_1C3FD
mov
dl, byte ptr [var_4+3]
mov
cl, al
shl
cl, 7
add
dl, cl
mov
byte ptr [var_4+3], dl
jmp
short loc_1C401
; --------------------------------------------------------------------------loc_1C3FD:
add
byte ptr [var_4+3], 80h
loc_1C401:
mov
ecx, [var_4]
mov
edx, ecx
shr
edx, 1Fh
add
ecx, ecx
or
edx, ecx
add
bl, al
cmp
word ptr [edi+esi*2], 0
mov
[var_4], edx
jnz
loc_1C344
mov
byte ptr [var_8], bl
loc_1C420:
mov
esi,
and
esi,
mov
ecx,
sub
ecx,
mov
eax,
shr
eax,
mov
ecx,
shl
edx,
pop
edi
or
eax,
mov
edx,
mov
and
movzx
mov
mov
shr
mov
and
movzx
mov
shr
mov
and
movzx
[var_8]
1Fh
20h
esi
edx
cl
esi
cl
edx
off_223F0
ecx, eax
ecx, 1Fh
si, byte ptr [edx+ecx]
ecx, [arg_4]
; will store the serial number into the arg_4
; It is passed to the function as pointer to Unicode array
; long 0Eh
[ecx], si
eax, 5
esi, eax
esi, 1Fh
si, byte ptr [edx+esi]
[ecx+2], si
eax, 5
esi, eax
esi, 1Fh
si, byte ptr [edx+esi]
PAGE 37
[ecx+4], si
eax, 5
esi, eax
esi, 1Fh
si, byte ptr [edx+esi]
[ecx+6], si
eax, 5
esi, eax
esi, 1Fh
si, byte ptr [edx+esi]
[ecx+8], si
eax, 5
esi, eax
esi, 1Fh
si, byte ptr [edx+esi]
eax, 5
[ecx+0Ah], si
eax, 1Fh
ax, byte ptr [eax+edx]
esi
[ecx+0Ch], ax
word ptr [ecx+0Eh], 0
ebx
esp, ebp
ebp
8
; --------------------------------------------------------------------------loc_1C4C0:
; CODE XREF: SerialCalculation+27_j
mov
edx, [arg_4]
pop
edi
pop
esi
mov
byte ptr [var_8], bl
mov
word ptr [edx], 0
pop
ebx
mov
esp, ebp
pop
ebp
retn
8
;SerialCalculation endp
} //and of __asm block
} //end of SerialCalculation function
You can now add all the digital, amazing effects and musics if you want, or leave rude and direct as it is, but the
essence is already here, the keygen works!!
PAGE 38
6. References
[1] SandBoxie 3.00.03, www.sandboxie.com or mirrored at
http://arteam.accessroot.com/tools/SandboxieInstall.exe
[2] Windows DDK version 6000.070702 help, available on Microsoft site.
[3] Portable Executable File Format Compendium v11 by Goppit, http://tutorials.accessroot.com
[4] CheckSum Fixer v1.0 by Shub-Nigurrath, http://arteam.accessroot.com
[5] Beginners Tutorial #9, Defeating Magic Byte Protection by Gabri3l, http://tutorials.accessroot.com
[6] Guide on How to play with processes memory, write loaders and Oraculums by Shub-Nigurrath,
http://tutorials.accessroot.com
[7] Coding a Serial Sniffer (Oraculum) by Anorganix, ARTeam e-zine #2, http://tutorials.accessroot.com
[8] A Journey to the Center of the Rustock.B Rootkit by Frank Boldewin, 20th January 2007,
http://reconstructer.org
[9] Improving the HideDebugger function by Shub-Nigurrath, http://tutorials.accessroot.com
7. Greetings
Greets goes out to the entire ARTeam family with its past, present and future members. A word of thank you to
the team members who took the time to read the beta version of this document and also found some important
errors. If youve got suggestions and/or comments about this tutorial or want to contribute with something new or
simply say hi, stop by at the forum and participate to the discussions there. Again, sorry for releasing this tutorial in
different versions, but I think additions deserve a new release of this documents.
Document History