主要原理
根据dll的导出表解析来定位函数在内存中的地址,所以我们只要解析导入表便可以获取到函数的真 正地址。但是在获取某些dll的地址时,会出现定位错真正的dll模块地址而出现获取函数地址死循环 的问题。如下图我从github上找了一个自实现GetProcessAddress的项目,项目地址为https://gith ub.com/ExByt3s/LoadLibrary-GetProcAddress-Replacements,我们根据结果可以看出当获取 kernel32.dll中的CreateRemoteThreadEx函数地址时,发现获取失败。其原因是没有针对API集进 行解析
API集形成的原因
针对不同的操作系统同一个api的具体实现不一定在同一个dll中,而api 集因此诞生,它是一个中间 dll,也类似于一种顶层封装。使我们在不同的windows操作系统下调用获取函数地址不会失败。如 下图为API 集的官网介绍
定位失败的原因
首先我们打开x64dbg查看在kernel32.dll中的CreateRemoteThreadEx的地址里存的内容是什么,发现为转发到了api-ms-win-core-processthreads-l1-1-0中的CreateRemoteThreadEx
api-ms-win-core-processthreads-l1-1-0.dll模块
我们调用函数获取api-ms-win-core-processthreads-l1-1-0.dll的模块基地址发现它还是给我们定 位到了kernel32.dll的基地址。导致我们陷入了一个死循环,一直在获取kernel32.dll中的 CreateRemoteThreadEx函数地址。那我们有什么办法解决呢?
API 集解析
API 集目前有四个版本:v2,v3,v4,v6,其本质上是在操作系统启动时加载了apisetschema.dll,并将.apiset节的内容映射到各个进程中去。如图为apisetschema.dll的各个节区块
API 集解析
根据API集的不同版本,对API集进行不同的解析。下图为API集 v6版本的API集的结构体,解析大 致流程为定位到PAPI_SET_NAMESPACE_ARRAY_V6,然后去除掉定位失败的dll名字的.dll与小版 本。然后找到对应的模块的API集信息后,再定位其信息的下一个API集。直到获取的模块与之前的 模块不同为止。
版本的API集的结构体
typedef struct _API_SET_NAMESPACE_ARRAY_V6 {
ULONG Version;
ULONG Size;
ULONG Flags;
ULONG Count;
ULONG EntryOffset;
ULONG HashOffset;
ULONG HashFactor;
API_SET_NAMESPACE_ARRAY_V6, * PAPI_SET_NAMESPACE_ARRAY_V6;
typedef struct _API_SET_NAMESPACE_ENTRY_V6 {
ULONG Flags;
ULONG NameOffset;
ULONG NameLength;
ULONG HashedLength;
ULONG ValueOffset;
ULONG ValueCount;
API_SET_NAMESPACE_ENTRY_V6, * PAPI_SET_NAMESPACE_ENTRY_V6;
typedef struct _API_SET_VALUE_ENTRY_V6 {
ULONG Flags;
ULONG NameOffset;
ULONG NameLength;
ULONG ValueOffset;
ULONG ValueLength;
} API_SET_VALUE_ENTRY_V6, * PAPI_SET_VALUE_ENTRY_V6;
自实现 GetProcessAddress兼容API 集
对于大型的免杀项目的api自实现,一定是需要兼容各个版本的,如图获取kernel32.dll中的 CreateRemoteThreadEx的函数地址成功
目前项目代码已经放到红队攻防的知识星球中了,红队攻防是一个致力于杀软对抗、二进制、恶意 软件分析、红队攻防、反逆向的星球! 有需要的可以加入了解交流。
微信搜索关注 "红队攻防" 扫一扫即可关注红队攻防!
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...