#include <stdio.h>
int main(int argc, char* argv[]){
printf("hello world\n");
return 0;
}
然后我将
/MT
选项用于发布模式以静态链接C运行时库。但是,据我所知,C运行时库仍调用较低级别的系统函数-例如,C运行时函数
printf
最终调用Windows API API。以及实际的函数体因此,即使我静态链接C运行时库,二进制文件也不包含
包括
WriteFile
或WriteFile
指令在内的整个例程... 核心部分仍在DLL中。下图描述了我的理解方式:
我想要的是将所有内容静态链接到单个EXE文件中。包括
kernel32.dll
和SYSENTER
消除了加载程序解析IAT和解析函数名称的必要性。下图描述了我想要的内容:
我知道在带
INT 0x2E
的Linux中这很简单。我所要做的就是给选项kernel32.dll
VS2010中有这样的选项吗?如果我误会了,请纠正我。
#1 楼
让我首先告诉您,由于众所周知的DLL的工作方式,您想要的东西将是不可能的。您可以使用PEBundle或dllpackager之类的工具尝试类似的操作,但通常(我肯定会说)会因众所周知的DLL(例如系统DLL甚至MSVC运行时DLL的不同版本)而失败。有关知名DLL的相关性和含义,请参见此内容。kernel32.dll
在Win32子系统中扮演非常特殊的角色,因为它有助于向子系统注册Win32线程和进程(csrss.exe
) 。实际上回答了OP的以下问题:
我并不是在寻找性能优势。我想,用这种方法,我可以像删除Linux剥离的二进制文件一样删除每个符号,并使反转变得更困难。
这样就没有意义了。您仍然只能导入单个函数,并使用复杂的方式导入DLL和/或解析函数。即隐藏从哪个DLL导入的功能。在黑客界比较流行的一件事是,对导出的函数名称进行哈希处理,然后自己遍历已加载映像的导出,对找到的每个函数名称进行哈希处理,然后与已知的哈希值进行比较。
这是一篇关于所需方法的好文章,因为shell代码对被劫持的进程中导入的函数地址一无所知。
正如Igor指出的那样,
kernel32.dll
将被加载到该进程中,并自动Vista的顺序也发生了变化(以前ntdll.dll
是PEB的DLL列表中的第一个aka LoaderData
)。因此,上面的文章中列出了确切的方法。其他几点:
如果您不想使用
LoadLibrary
(或其对应的ntdll.dll
)动态加载DLL,则可以在IAT中保留对单个导入函数的引用-这是某些可执行打包程序的实现方式。,首先要解析
LoadLibraryA
,加载所需的DLL,然后使用已解决的GetProcAddress
(或kernel32.dll
上已使用并已在本文中概述的您自己的方法)加载更多功能。使其对熟练/经验丰富的逆向工程师更加困难。他们中的大多数人都会看到类似的方案;)...动态分析将轻松揭示您的技巧,并使逆向工程师能够解决它们。作为替代,您可以诉诸于通过编写简化的反汇编程序来创建系统调用号,该反汇编程序可以将索引提取到SSDT(系统服务描述符表)中,然后自己完成其余工作。这已经有很长的记录了,因为这是人们在内核模式驱动程序中挂钩索引时通常用来在SSDT中找到索引的方式。大致来说,如果您在
ntdll.dll
中有指向SSDT索引的函数的指针,则应检查一下假设,然后检索适当的值。在Windows NT 4到2003(32位)中,它看起来像 B8 ?? ?? ?? ??
其中
B8
代表mov eax, ????????
,问号是SSDT的索引。因此,在检查了B8
之后,您将跳过它并获取下一个DWORD。使用C代码的示例:但是我看不到任何优势-无论是从性能角度还是在阻止逆向工程方面都没有优势。评论
实际上,您唯一需要的导入是GetProcAddress,因为可以通过GetProcAddress(“ LoadLibrary”)进行导入。
–彼得·弗里
13年5月23日在15:44
#2 楼
Windows内核与Linux或OS X不同,它不使用跨版本的一致syscall编号。即使发布Service Pack,数字也可能会更改。例如,NtReadFile
系统调用在Windows NT 4上是0x0086
,但在Windows 7上是0x0111
(完整列表请参见此处)。这就是为什么所有正确的程序都使用
kernel32.dll
(或ntdll.dll
)执行实际调用的原因-确保DLL使用与内核匹配的syscall号。 顺便说一句,通过在IAT中不列出
kernel32.dll
,您将不会节省任何内容-系统加载程序始终将其映射到Win32进程中(从Windows 2000 IIRC开始)。评论
我以为Windows系统调用编号与Linux相同。感谢您提供的信息,这对我的理解很有帮助!
–daehee
13年5月22日在10:39
@daehee:每隔一段时间就会更改一次。这就是文件列出ELF文件内核版本的原因。
– 0xC0000022L♦
2013年9月18日下午16:51
评论
答案显然是“否”。您将必须编写自己的特定于操作系统的syscall层。问题是:为什么不使用标准的CRT?有什么优势?谢谢。实际上,我并不是在寻找性能优势。我以这种方式,可以像删除Linux剥离的二进制文件一样删除每个符号,并使反转变得更困难。
@daehee:这使您的问题有了一个全新的视角。
总体来说,您的描述是正确的,但是您需要添加另一层,即NT本机api:fread(msvcrt)-> ReadFile(kernel32)-> NtReadFile(ntdll.dll)-> kernel
经过足够的努力,您也许可以执行嵌入式Windows功能,但随后您便会绑定到该特定的Windows版本,并且可能会侵犯MS的版权。