Copy Link
Add to Bookmark
Report

xine-2.009

eZine's profile picture
Published in 
Xine
 · 26 Apr 2019

  


/-----------------------------\
| Xine - issue #2 - Phile 009 |
\-----------------------------/

; GetProcAdd for Kernel32 - finding Kernel32 API's
; by jhb

; One of the major hurdles for Virii writers who want to extend there selves
; to Win95 virii, is the ability to call the Win95 API. But the usual way to
; call these API is to have them already link and in the import area of the PE
; file. So how do you call the API if you do not have them linked at run time?
; Well VLAD show us we can hard code the API address's but if Win95 changes
; the kernel location ,we have a problem. Next VLAD shows us a way to "patch"
; the import area to get getproccaddress and loadlibrary, this allows us to get
; the address of all the import by name API. Another way is demo'ed in this
; code by assuming one thing the kernel address (0BFF70000h) we can use the
; info in the PE file format of the Kernel32 to locate any API named/ordinal.
; This means we can have access to any API that is Exported... Well a modified
; form of the routine is used in the Puma virus to import all the need API.
; The only problem is the hardcoded Kernel32 address. Well after I wrote this
; code I found that if the program imported any kernel32 routine then the
; address was located in the entry of the Kernel32 in the import area.
; Here is a diagram that hopefully illustrates what I am poorly explaining
; an entry in the import table is like so:
;
; offset b4 runtime runtime
; 0 rva Pnter to first API imported same
;
; 4 000000 timedate of DLL
;
; 8 000000 load address of
; the dll
;
; C rva pnter to dll name same
;
; 10 rva Pnter to first API imported address to jmp
; tble to API
;
; Well to some this is still nonsense, read the PE format docs and it mite
; make more sense ;), The important thing is that the Dll address is there
; and can be used. Problem here if the file does not have a Kernel API,
; doubtful since to even end the file you use ExitProcess. Second problem
; if the file is "Binded" this means the file has the import address already
; loaded into it, Basically this can be checked b4 runtime offset 4 already
; have a date and time offset 8 has FFFFFFF in it, but change the date time
; field and then all is ok, the file is no longer "binded". This way would
; just setup a routine to get the kernal address and then run the regular
; routine here to get the Address of whatever kernel we need.
; Anyway this routine is just a simple example I use to get the address of
; routines I want to test ideas on. Getting the CallVxd0 or ordinal 1
; of the Kernel this gives us access to VXD routines like Vwin32_int21Dispatch
; so with one routine you could infect the a file using int 21 calls. Well
; this should work in theory. Well I hope this routine helps others understand
; the writing of Virii in Win95.
;
; Yes I know that if the ordinal is the last routine found there is garbage
; in the title of the box but oh well you fix it it demos the idea ok
; jhb 1/97

; The main idea is to find the Kernel32 loaded address which is the
; number we will need to add to all the rva to get the actual location in
; memory now located the import data area by using the info in the data
; directory the import data is located at the 78h bytes into the PE header
; now we take this rva add the kernel and we have the import segment.
; now we get the pointers to the 3 arrays nameindex, functionindex,
; AddressofFunction we also need the ordinal base but thats easy also
; Each index is a pointer to the next bit of info to find the Address of the
; function. First take the Name and find which string it matches to now use
; this number as an index into the ordinals now use the ordinal as an index
; into the Array of Funcutions address then ya got it. Well I doubt that made
; sense I hope but doubt my comments in the code help
;
;
; To compile:
; tasm32 /ml /m3 getadd,,;
; tlink32 /Tpe /aa /c getadd,getadd,, import32.lib
;


; just trying to visualize how i am storing all the data on the stack
;
; -14h
; -10h
; -0Ch
;holders -10
;ret_address -8
;old_bp -4
Export_rva equ 0
kern1 equ Export_rva + 4
baseF equ kern1 + 4
AddFunc equ baseF + 4
AddName equ AddFunc + 4
Nindex equ AddName + 4
AddOrd equ Nindex + 4
limit equ AddOrd + 4
Where equ limit + 4
Looking equ Where + 4
worksp equ Looking + 4

.386
locals
jumps
.model flat ,stdcall


;Working version of a get address routine ends with di containing the
;address of the process
;set to work with KERNEl32.dll and nothing else
;will only look till there is no more names to check
;

;Define the needed external func tions and constants here.

extrn ExitProcess:PROC
extrn MessageBoxA:PROC ;note in the user32.dll


.data ;the data area
title1 db 'this is a title',0
mess db 'this is a message',0
storage dd 4 dup(0)

.code ;executable code starts here

HOST:

jmp OverData
;fake data
kern dd 0BFF70000h ;must add to all rva's

;ok below is the functions we are going to look for
;format is the standard end in 0 if you pass an ordinal
; give me the ascii = of the number in the first 2 bytes then
; the number in hex you looking for.
LookFor db 'ReadFile',0
db 'ExitProcess',0
db 39h, 30h, 90d ;'AllocLSCallback',0
last db 30h, 31h, 01d
db 0Bh
db 0


OverData:
mov esi,offset LookFor ;where the list of functions
;is

mov eax,4 ;how many functions


call GetProcAdd ;on return the stack wil
;have addresses in it
;last request first pop
;format LIFO ;)


;-

;edi = the address of the function in question
;for this test case we will use a dialog box and show the
;the last function found and its address


Box_it:

;=====================================================================
;this simply makes the value in edi converted to a ascii string with a null
; 0 at the end Borlands version was too long


push edi
mov edi,offset mess
mov cx,1ch

digit_loop:
pop eax
push eax

shr eax,Cl
and ax,000fh
sub cx,4
cmp al,9
jle number

sub al,0ah
add al,41h
jmp letter

number:
or al,30h
letter:
stosb
cmp cx,0fffCh
jne digit_loop
mov al,0
stosb

pop edi

;now we call the MenuBox API
;------------------------------------------------------------------------
mov eax, -1
push eax

mov eax, offset last ;
push eax ;

mov eax,offset mess ;
push eax ;

mov eax,0
push eax

call MessageBoxA

;just some playing around
;push offset return_here

;push 0bff638d9h
;ret

;return_here:



fini: ;left over from a Teacher who use to teach me C++

push LARGE -1
;call dword ptr edi ;when I used the routine to locate
;the ExitProcess address
call ExitProcess ;this simply terminates the program

;===========================================================================
GetProcAdd:
;edi = where to place the address ;Where
;esi = the list of address's delimited by Zero end in 0Bh ;Looking
;

pop ebx ;set up and save
;some storage for the
shl eax,2 ;routine
sub esp,eax ;
mov edi, esp ;
;
push ebx ;
;
push ebp ;
sub esp,worksp ;
mov ebp,esp ;


mov [ebp + Where],edi ;save where will store them
mov [ebp + Looking],esi ;save which ones looking fo

mov esi,dword ptr [kern]

lodsw
cmp ax,'ZM' ;we assume Bff70000h for location
jne Not95 ;of the Kernel

xor eax,eax ;ok its the start of a exe file
add esi,3Ah ;get pointer to the PE start
lodsw

mov esi,dword ptr [kern] ;if this is not true get out
add esi,eax ;now load that word
lodsd ;

cmp ax,'EP' ;same thing if this is not true
jne Not95 ;something is wrong

;found the PE header
; sub esi,4 ;back up si to the PE header
; ;

mov [ebp + kern1],eSI ;save the address of the PE header
; no reason thouht i might need it

add esi,74h ;should be 78h but the last lodsw
lodsd ;should be rva to the .edata

mov ebx, dword ptr [kern]

add eax,ebx ;should be the .edata area
;offset to the to name of dll
add eax,10h ;
mov esi,eax ;get us to the base
;
; ok found the .export area now get the info we need to find
; the address

lodsd
mov [ebp + baseF],eax ;this is the starting ordinal that
;that all must be added to
;usualy 1 for kernel32

lodsd ;total number of exported functions
;by name and ordinal

lodsd
mov [ebp + limit],eax ;how many functions are exported
;by name this is the limit of how
;many we will search for

;the next three are all RVA's to the
;fields so we need to add the offset
;them
lodsd ;this is the address to
add eax,dword ptr [kern] ;an array of pointers to the
mov [ebp + AddFunc],eax ;entry point rva's of each

lodsd ;this is the RVA to ascii names
add eax,dword ptr [kern] ;of each named exported fuction
mov [ebp + AddName],eax ;

lodsd ; rva points to array of words
add eax,dword ptr [kern] ;which are the export ordinals
mov [ebp + AddOrd],eax ; - the base

;ok we have everthing we need to go ahead and locate the address's of the
;KERNEL32.dll functions

mov ebx,[ebp + Looking] ;get address of the first name



LookLoop:
mov esi,[ebp + AddName] ;get the first rva pointer to a name
mov [ebp + Nindex],esi ;

mov edi,[esi] ;now make it a true pointer to the
add edi,[kern] ;name by adding the offset

mov ecx,0 ;sets the counter to 0


TryAgain:
mov esi,ebx ;what function we are looking for
;now simple cmp strs


test byte ptr [ebx], 00110000b ; check if we have a ordinal
jne UseOrdinal ;instead of a String here


MatchByte:
cmpsb
jne NextOne ;not it try next nameof fucntion

cmp byte ptr [edi],0 ;if equal to 0 we found a match
je GotIt ;

jmp MatchByte ;nope try next byte

NextOne:
inc cx
cmp cx,[ebp + limit]
jge not_found

add dword ptr [ebp + Nindex],4 ;get the next pointer rva
mov esi,[ebp + Nindex] ;and try again
mov edi,[esi] ;
add edi,[kern] ;
jmp TryAgain ;

;---------------------------------------------------------------------
GotIt:
;note if not a match is found the all other from then on in are blank
;in other words dont mispell ,or ask for for a function that is not in
; KERNEL32
;esi = the 0 at the end of the name of the strings given to us to look for
;
;cx = the index into the AddOrd
;take Nindex * 4 + [AddOrd] = Ordinal
;Ordinal * 4 + [AddFunc] should be the rva to the fuction

mov ebx,esi ;get set for next search routine
inc ebx ;

shl ecx,1 ;*2 looking into a word array
mov Esi,[ebp + AddOrd]
add Esi,ecx
xor eax,eax
mov ax,word ptr [esi]

jmp GotOrdinal
;here ax equals the ordinal - the base
;if ordinal is passed to hear then we should be able to skip
;searching for a name and hit here
;not sure of course but it tested on a few that I tried
;

UseOrdinal:

mov al, byte ptr [ebx + 2] ;I do not check for
cbw ;bad ordinals so this
cwde ;may return wrong anwsers
inc ebx ;if wrong ordinal sent
inc ebx
inc ebx


GotOrdinal:
shl eax,2 ;*4 looking into a dword array
mov esi,[ebp + AddFunc]
add Esi,eax

mov Edi,dword ptr [esi]
add Edi,[kern]

push ebp

mov esi, [ebp + Where]
mov ebp,esi
mov [ebp ],edi

pop ebp
add dword ptr [ebp + Where],4

cmp byte ptr [ebx],0bh
jne LookLoop

jmp over_error

Not95:
xor esi,esi ;if the header of the kernel
;is not there forget it, its not
; the Win95 we know and love ;)

not_found: ; String pass to us is not a
xor edi,edi ; valid fucntion name

over_error:

ADD ESP,worksp
pop ebp

ret
;----------------------------------------------------------------------------


end HOST


← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT