flat assembler
Message board for the users of flat assembler.
Index
> Windows > Working Win32 PE exe without an import table |
Author |
|
Furs 30 Aug 2017, 10:27
Epic hack
At first I thought it used hardcoded system calls for specific Windows versions. |
|||
30 Aug 2017, 10:27 |
|
revolution 30 Aug 2017, 10:38
These no-imports files have been around for a while now, there are some old examples already on this board. IIRC they only work on some versions of Windows. Win2000 and WinXP did things differently and one would run them while the other wouldn't. It's been a while since I tested any of these, so perhaps Win7, 8, 8.1 and 10 have changed things in the loader?
|
|||
30 Aug 2017, 10:38 |
|
Tomasz Grysztar 30 Aug 2017, 13:09
It might be worth it to add a reference to the old (12 years old!) discussion: https://board.flatassembler.net/topic.php?p=27846
|
|||
30 Aug 2017, 13:09 |
|
Marut 30 Aug 2017, 23:40
Oh cool, I see you used more or less the same approach revolution, with some differences here and there. So I guess mine wouldn't work on Win2K as well.
Vasilev instead walked through the PEB, it seems. I don't know what changes were made to the loader, but from a quick test it seems that in Windows 10 ntdll.dll, KERNEL32.DLL and KERNELBASE.DLL are always mapped inside a process's virtual space; if the process is 32-bit and the OS is 64-bit, wow64.dll, wow64win.dll and wow64cpu.dll are loaded too. |
|||
30 Aug 2017, 23:40 |
|
revolution 01 Sep 2017, 16:02
Also, some AVs panic when they see non-standard exe file like these. So even if the OS itself successfully runs it, other users may find their AV blocks it. And then you get an angry messages accusing your software of being malware.
|
|||
01 Sep 2017, 16:02 |
|
Marut 01 Sep 2017, 20:32
Yeah, tell me about it. I have Avast, whenever I compile anything my AV delays the execution of the program to scan it first, I have to interrupt the scan manually every time. Not only with FASM, even with MSVC++.
And to add insult to injury, small executables like those produced with FASM have a higher chance to trigger the heuristic algorythms inside Avast; when I downloaded the FASM64 pack it was a parade of false positives. If I want to program without losing my mind, I just have to turn the AV off temporarily. |
|||
01 Sep 2017, 20:32 |
|
emily 02 Sep 2017, 00:33
Very cool! A tip for getting the base of kernel32.dll from the loader return address on the stack is to align the return address to 64k and then go back one 64k increment. this works because all modules are located on a 64k boundary.
Code: IMG_BASE = 10000h entry: mov eax, [esp] xor ax, ax ; align to 64k lea ebx, [eax - IMAGE_BASE] ; go back 64k You can also get tricky and jump directly to the PE header (+100h) or optional header by doing something like Code: lea ebx, [eax - IMAGE_BASE + 100h] |
|||
02 Sep 2017, 00:33 |
|
revolution 02 Sep 2017, 09:16
emily wrote: Very cool! A tip for getting the base of kernel32.dll from the loader return address on the stack is to align the return address to 64k and then go back one 64k increment. this works because all modules are located on a 64k boundary. |
|||
02 Sep 2017, 09:16 |
|
fasmnewbie 04 Sep 2017, 18:38
Some code you have back there, Marut. Refreshing.
To save you from risk of violations, you could change your STEP to 0x40000. This works for both 64-bit and 32-bit versions of Windows. kernel32.dll is apparently considered an application and not a DLL if you know what I mean. ANDing it with -0x40000 will take you straight to the base address. Just my 2 cents worth. |
|||
04 Sep 2017, 18:38 |
|
Marut 08 Sep 2017, 20:57
@emily: thank you. Yes, that's what I'm saying in the last bullet of my first post; in fact, the original draft of the program had to work that way, because I didn't have an exception handler set up yet. In the end I opted to use STEP = 4k for the reason explained by revolution.
@fasmnewbie: Thanks, I didn't know that. Anyway, access violations don't worry me (SEH is there for a reason) as much as the risk of missing the MZ header. I kinda chose the "paranoid" route here. |
|||
08 Sep 2017, 20:57 |
|
fasmnewbie 09 Sep 2017, 19:33
Marut, I think your approach is more towards completeness rather than "paranoid". I developed about the same (incomplete) code in 64-bit mode some time back and never hit any incompatibility wall on 64-bit win with STEP = 0x400000. But only tested it on 2 machines. Could behave differently on others though. Gave up early because the binary output really bleeds my eyes.
Added some more descriptive comments... not sure if it offers anything new compared to yours. Attempted to access msvcrt.dll from it. No SEH. No Ordinals. p/s I think Tomasz know more about this when creating that FASM internal PE linker. Should ask him. Code: ;----------------------------------- ;Creating .exe by calling ;the 64-bit DLLs directly without header ;Lazy string compare. Just for fun. ;----------------------------------- format PE64 console entry main KernelBase dq 0 PEHeader dq 0 PEOptHeader dq 0 Directory dq 0 IMG_EXPORT dq 0 AddrOfNames dq 0 AddrOfFunctions dq 0 NumOfFunctions dq 0 LoadLibAddr dq 0 ExitProcessAddr dq 0 GetProcAddr dq 0 FreeLibAddr dq 0 s db 'ExitProcess',0 t db 'LoadLibraryA',0 m db 'msvcrt.dll',0 x db 'printf',0 g db 'GetProcAddress',0 c db 'getchar',0 l db 'FreeLibrary',0 h db 'Hello World, no header',0ah,0 BASE = 0x40000 main: mov rsi,[rsp] ;Somewhere in kernel32.dll and rsi,-BASE ;Point to KernelBase Address mov [KernelBase],rsi movzx rbx,byte[rsi+3ch] add rsi,rbx ;Points to PEHeader mov [PEHeader],rsi add rsi,4*6 ;Points to PEOptHeader mov [PEOptHeader],rsi add rsi,112 ;Offsets from PEOptHeader mov [Directory],rsi ;96 for win32 mov ebx,[rsi] ;RVA to Export mov rax,[KernelBase] add rax,rbx ;Point to IMAGE_EXPORT_DIRECTORY mov [IMG_EXPORT],rax ;save it mov ebx,[rax+4*6] mov [NumOfFunctions],rbx add rax,4*8 ;point to "AddrOfNames" field mov [AddrOfNames],rax mov ebx,[rax] ;get RVA to Name mov rax,[KernelBase] mov ebx,[rsi] add rax,rbx add rax,4*7 mov [AddrOfFunctions],rax ;Get the kernel32.dll function addresses ;to be used in the subsequent code get_all_address: mov rbx,g call Probe_Function_Address mov [GetProcAddr],rax mov rbx,t call Probe_Function_Address mov [LoadLibAddr],rax mov rbx,s call Probe_Function_Address mov [ExitProcessAddr],rax mov rbx,l call Probe_Function_Address mov [FreeLibAddr],rax ;Test and run all functions with the ;loaded addresses. Observe calling conventions run_all: sub rsp,40 ;Load "msvcrt.dll" library ;Base Address in RAX mov rcx,m call [LoadLibAddr] mov r15,rax ;Get "printf" address from "msvcrt.dll" ;Address in RAX mov rdx,x ;Function string to find mov rcx,rax ;Base Address of msvcrt.dll call [GetProcAddr] ;Call "printf" from "msvcrt.dll" mov rcx,h call rax ;call printf ;Get "getchar" address from "msvcrt.dll" ;Address in RAX mov rcx,r15 ;Address of msvcrt.dll mov rdx,c ;Function string to find call [GetProcAddr] call rax ;call getchar ;Call "FreeLibrary" from "kernel32.dll" ;Requires input from LoadLibrary's return mov rcx,r15 call [FreeLibAddr] add rsp,40 done: mov rcx,0 call [ExitProcessAddr] ;----------------------------------- ;Probe_Function_Address RBX/1 ;Get a kernel32.dll's function address ;----------------------------------- ;RBX : pointer to function string to probe ;----------------------------------- ;Return : RAX - Address of function ;NOTE : This doesn't load a library ; Load only once the address is known ; : Probe kernel32.dll APIs only ;----------------------------------- align 16 Probe_Function_Address: mov rax,[AddrOfNames] ;address of RVA from IMPORT mov edx,[rax] ;Get the RVA field mov rax,[KernelBase] ;Start from BASE add rax,rdx ;Go Straight to Array of AddrOfNames mov rcx,[NumOfFunctions] mov rbx,qword[rbx] mov rsi,0 .fString: mov edx,dword[rax] add rdx,[KernelBase] mov rcx,[rdx] cmp rbx,rcx je .fAddress add rax,4 add rsi,1 sub rcx,1 jnz .fString .fAddress: mov rax,[IMG_EXPORT] add rax,4*7 ;point to "AddrOfFunctions" field mov ebx,[rax] ;get the field value (RVA) mov rax,[KernelBase] ;start from BASE add rax,rbx ;BASE + RVA of AddrOfFunctions mov ecx,[rax+rsi*4] ;Get RVA mov rax,[KernelBase] ;Start from BASE add rax,rcx ;BASE + RVA ret |
|||
09 Sep 2017, 19:33 |
|
jochenvnltn 16 Oct 2017, 08:56
Cool But there is no need to use LoadLibrary on user32.dll
Code: proc GetUser32 mov esi, [fs:30h] ; get a pointer to the PEB mov esi, [esi+0Ch]; PEB.lpLoaderData mov esi, [esi+1Ch]; PEB_LDR_DATA.InInitializationOrderModuleList @@: mov ecx, [esi+8h] ; LDR_MODULE.BaseAddress mov edi, [esi+20h]; LDR_MODULE.BaseDllName+UNICODE_STRING.Buffer mov esi, [esi] cmp dword [edi+08h],0320033h jne @b mov eax,ecx ret endp |
|||
16 Oct 2017, 08:56 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.