获取DLL基址

windbg查看dll基址

fs寄存器 -> TEB -> PEB -> PEB_LDR_DATA -> LIST_ENTRY -> LDR_DATA_TABLE_ENTRY -> dll_base

syscall

首先写一个简单的syscall的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <Windows.h>
#include "winternl.h"
#pragma comment(lib, "ntdll")

EXTERN_C NTSTATUS SysNtCreateFile(
PHANDLE FileHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PIO_STATUS_BLOCK IoStatusBlock,
PLARGE_INTEGER AllocationSize,
ULONG FileAttributes,
ULONG ShareAccess,
ULONG CreateDisposition,
ULONG CreateOptions,
PVOID EaBuffer,
ULONG EaLength);

int main()
{
FARPROC addr = GetProcAddress(LoadLibraryA("ntdll"), "NtCreateFile");

OBJECT_ATTRIBUTES oa;
HANDLE fileHandle = NULL;
NTSTATUS status = NULL;
UNICODE_STRING fileName;
IO_STATUS_BLOCK osb;

RtlInitUnicodeString(&fileName, (PCWSTR)L"\\??\\c:\\temp\\test.txt");
ZeroMemory(&osb, sizeof(IO_STATUS_BLOCK));
InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE, NULL, NULL);

SysNtCreateFile(
&fileHandle,
FILE_GENERIC_WRITE,
&oa,
&osb,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_WRITE,
FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);

return 0;
}

编译生成exe文件,然后丢进windbg里面进行调试
windbg常用的几个指令

  1. bp(breakpoint)
  2. g(goto)
  3. dt(dump using type information)
  4. dv(dump local variables)
  5. k(stacktrace)

这样的话,我们先来分析下TEB的数据结构dt _TEB
TEB数据结构
可以发现在0x060的偏移处存放的是进程环境块PEB的指针

接着我们继续跟进,插卡PEB的数据结构dt _PEB
PEB数据结构
可以看到0x018的偏移处存放的是PEB_LDR_DATA结构体的指针

继续跟进PEB_LDR_DATA数据结构
PEB_LDR_DATA数据结构
可以看到在0x020的偏移出存放的是_LIST_ENTRY指针
根据其名字变量名InMemoryOrderModuleList可以看出是按照内存中顺序的模块链表

继续跟进就能看到该_LIST_ENTRY为双向链表
LIST_ENTRY
既然是双向链表,那肯定继续指出了下一步的指针,但这里无法明确的看出,我们需要去MSDN进行查询

通过查询MSDN
可以知道,这里对应的是LDR_DATA_TABLE_ENTRY这个结构体

那我们继续跟进这个结构体dt _LDR_DATA_TABLE_ENTRY,也就是该链表实际指向的内容
LDR_DATA_TABLE_ENTRY
可以看到这里偏移0x018的位置,存放的就是DLL基地址,同时还存有FullDllName和BaseDllName可以帮助我们区分是哪个DLL

代码遍历模块链表

模块链表是一个双向循环链表,以下以遍历InLoadOrderModuleList举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

typedef struct _LIST_ENTRY
{
_LIST_ENTRY* Flink;
_LIST_ENTRY* Blink;
}_LIST_ENTRY;

typedef struct _UNICODE_STRING
{
unsigned short Length;
unsigned short MaximumLength;
wchar_t* Buffer;
};

int main()
{
int* pPEB = NULL;

__asm
{
push eax
mov eax,fs:[0x30]
mov pPEB,eax
pop eax
}

int* pIDR = (int*)(*(pPEB + 0x03)); //0x03 * 4 = 0x0c

_LIST_ENTRY* pInLoadOrderModuleList = (_LIST_ENTRY*)(pIDR + 0x03); //0x03 * 4 = 0x0c

_LIST_ENTRY* pHead, *p;
p = pHead = pInLoadOrderModuleList->Flink;

int count = 0;
do
{
printf("%d: ", count++);
_UNICODE_STRING* pBaseName = (_UNICODE_STRING*)(((int)p) + 0x2c);
if (pBaseName->Buffer)
wprintf(L"%s ", pBaseName->Buffer);
printf("0x%x\n", *((int*)(((int)p) + 0x18)));
//
p = p->Flink;
} while (p != pHead);

return 0;
}

获取DLL基址
https://glacierrrr.online/2022/11/12/获取DLL基址/
作者
Glacier
发布于
2022年11月12日
许可协议