我一直在Delphi中玩一些不允许使用RTL的东西.这是一种dll.
在分离PE(可移植可执行文件)文件格式之后,我意识到所有PE文件都有一个"入口点".这是Windows在加载模块(exe或dll)后调用的第一件事.
该名称的功能,位于此入口点,并且它的隐含参数,取决于PE的一种,它是:
动态链接库(*.dll): DllMain
function DllMain(hinstDLL: HINST; fdwReason: DWORD;
lpvReserved: Pointer): BOOL; stdcall;
Run Code Online (Sandbox Code Playgroud)可执行(*.exe): WinMain
function WinMain(hInstance: HINST; hPrevInstance: HINST;
lpCmdLine: LPSTR; nCmdShow: Integer): Integer; stdcall;
Run Code Online (Sandbox Code Playgroud)设备驱动程序(*.sys): DriverEntry
function DriverEntry(DriverObject: PDriverObject;
RegistryPath: PUnicodeString): NTSTATUS; stdcall;
Run Code Online (Sandbox Code Playgroud)在Delphi中,此入口点是位于主项目文件中的代码.
在DLL的情况下,可以读取传递给我们的"DllMain"的参数LoadLibrary.如果在EntryPointAddress上放置一个断点:

你可以在堆栈上看到三个参数:

您所要做的就是捕获它们:
library Project1;
function DllMain(hinstDLL: HINST; fdwReason: Cardinal; lpvReserved: Pointer): Integer; stdcall;
begin
Result := 1; //Windows uses FALSE=0, TRUE=1. Delphi uses False=0, True=-1
end;
begin
//Code in here is run during DllMain.
//i.e. DllMain does not return until this code completes.
asm
{ Get the parameters to DllMain that Windows passed to us:
[ESP+4] hinstDLL
[ESP+8] fdwReason
[ESP+12] lpvReserved
}
MOV eax, [ESP+12]; //push lpvReserved onto the stack
PUSH eax;
MOV eax, [ESP+8]; //push fdwReason onto the stack
PUSH eax
MOV eax, [ESP+4]; //push hinstDLL onto the stack
PUSH eax;
CALL DllMain; //Call our DllMain function
//DllMain leaves BOOL result in EAX
end;
end.
Run Code Online (Sandbox Code Playgroud)
问题是那里不仅仅是我的代码.编译器在项目文件中的代码块之前和之后插入隐藏代码:

基本上,真正的 DllMain代码包含:
function DllMain(hinstDLL: HINST; fdwReason: Cardinal; lpvReserved: Pointer): LongBool; stdcall;
begin
SysInit._InitLib(InitTable, hinstDLL, fdwReason, lpvReserved);
asm
MOV eax, [ESP+12]; //push lpvReserved onto the stack
PUSH eax;
MOV eax, [ESP+8]; //push fdwReason onto the stack
PUSH eax
MOV eax, [ESP+4]; //push hinstDLL onto the stack
PUSH eax;
CALL DllMain; //Call our DllMain function
//DllMain leaves BOOL result in EAX
end;
System._Halt0;
end;
Run Code Online (Sandbox Code Playgroud)
现在,这个序言调用_InitLib做一些发泄与破坏试图拉的价值观hinstDLL和fdwReason; 但是这不是一个不可克服的问题(例如,你仍然可以在找到他们EBP+8,+12和+16).
但我的问题是RTL链接到并不总是可用的代码.查看导入目录表,您可以看到它需要:
user32.dll(例如MessageBoxA)kernel32.dll(例如VirtualAlloc,VirtualFree,CloseHandle)是否有一个编译器选项或定义,可以去除所有的内核System._InitLib和System._Halt0?或者只是让编译器不要将它们放入:
function DllMain(hinstDLL: HINST; fdwReason: Cardinal; lpvReserved: Pointer): LongBool; stdcall;
begin
SysInit._InitLib(InitTable, hinstDLL, fdwReason, lpvReserved);
//...
System._Halt0;
end;
Run Code Online (Sandbox Code Playgroud)
对于知道创建它们的编译器来说,这显然是一个特殊的智能.而且,如果它是一个库或应用程序二进制文件,那么隐含在EntryPointProcedure中的内容会发生变化.
WinMain参数的情况该WinMain入口点记录,以传递四个参数:
function WinMain(hInstance: HINST; hPrevInstance: HINST;
lpCmdLine: LPSTR; nCmdShow: Integer): Integer; stdcall;
Run Code Online (Sandbox Code Playgroud)
hInstance: HINSTANCEhPrevInstance: HINSTANCElpCmdLine: LPSTRnCmdShow: Integer这就是为什么我无法弄清楚为什么参数没有传递给EntryPointFunction的原因:

我正在进一步调试并进一步回到堆栈中.我试过其他调试器.Windows只是没有将适当的参数传递给入口点功能.然后我找到了答案:
操作系统调用没有参数的函数
在真正的Windows .exe入口点函数为:
DWORD CALLBACK RawEntryPoint(void);
Run Code Online (Sandbox Code Playgroud)
又名:
function RawEntryPoint(): DWORD; stdcall;
Run Code Online (Sandbox Code Playgroud)
WinMain的参数来自哪里,如果它们没有传递给原始入口点?
语言启动代码通过询问操作系统来获取它们:
- 可执行文件的实例句柄来自
GetModuleHandle(NULL)- 命令行来自
GetCommandLine- 而且
nCmdShow来自GetStartupInfohPrevInstance总是NULL
这就解释了这一点.
使用普通编译器/RTL 无法实现您想要的效果。编译器期望存在System和SysInit单元,并且确实使用这些单元为许多语言功能提供运行时支持。例如,字符串是通过System单元中实现的支持功能来实现的语言功能。
如果您提供编译器可接受的替换System和SysInit单元,则可以删除对用户模式模块的依赖关系。然而,这并不是为了假心。
由于您似乎希望编写内核模式驱动程序代码,因此我建议使用 FPC。
| 归档时间: |
|
| 查看次数: |
416 次 |
| 最近记录: |