腾讯游戏安全大赛2024决赛题解
决赛打五天,是真的顶级,但是五天比一年学的东西都多...本题[解题附件](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/attachment.zip)自取
<!--more-->
## 2024腾讯游戏安全竞赛决赛题解
### 分析
#### 自行加载loader.sys, 找到用户名为administrator的KEY,作为答案提交(1分)
Key 和 User 默认读 `C:\card.txt`,如果找不到或者是错误,那么加载会失败,于是想到 hook NtCreateFile 获取到文件句柄,再 hook NtReadFile 找到文件内容写入的地址。
```C
#include <ntifs.h>
#include <ntdef.h>
#include <ntstatus.h>
#include <ntddk.h>
#define MAX_BACKTRACE_DEPTH 20
#define SYMBOL L"\\??\\xia0ji2333"
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)
UINT64 BaseAddr=NULL, DLLSize=0;
void DeleteDevice(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start delete device\n"), __LINE__);
if (pDriver->DeviceObject) {
UNICODE_STRING Sym;
RtlInitUnicodeString(&Sym, SYMBOL);//CreateFile
kprintf(("Line %d:xia0ji233: Delete Symbol\n"), __LINE__);
IoDeleteSymbolicLink(&Sym);
kprintf(("Line %d:xia0ji233: Delete Device\n"), __LINE__);
IoDeleteDevice(pDriver->DeviceObject);
}
kprintf(("Line %d:xia0ji233: end delete device\n"), __LINE__);
}
HANDLE FileHandler = NULL;
char newcode[] = {
0x48,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov rax,xxx
0xFF,0xE0//jmp rax
};
char oldcode[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
char newcode2[] = {
0x48,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov rax,xxx
0xFF,0xE0//jmp rax
};
char oldcode2[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
char* target;
char* target2;
KIRQL WPOFFx64()
{
KIRQL irql = KeRaiseIrqlToDpcLevel();
UINT64 cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
_disable();
return irql;
}
void WPONx64(KIRQL irql)
{
UINT64 cr0 = __readcr0();
cr0 |= 0x10000;
_enable();
__writecr0(cr0);
KeLowerIrql(irql);
}
NTSTATUS Unhook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target = oldcode;
}
WPONx64(irql);
return STATUS_SUCCESS;
}
NTSTATUS Unhook2() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode2); i++) {
target2 = oldcode2;
}
WPONx64(irql);
return STATUS_SUCCESS;
}
NTSTATUS Hook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target = newcode;
}
WPONx64(irql);
return STATUS_SUCCESS;
}
NTSTATUS Hook2() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode2); i++) {
target2 = newcode2;
}
WPONx64(irql);
return STATUS_SUCCESS;
}
PDRIVER_OBJECT g_Object = NULL;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;//驱动的进入点 DriverEntry
ULONG SizeOfImage;
UNICODE_STRING FullDllName;//驱动的满路径
UNICODE_STRING BaseDllName;//不带路径的驱动名字
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef NTSTATUS (* FuncPtr) (
_Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG CreateOptions,
_In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
_In_ ULONG EaLength
);
typedef NTSTATUS (* FuncPtr2 )(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_In_opt_ PLARGE_INTEGER ByteOffset,
_In_opt_ PULONG Key
);
ULONGmyCreateFile(_Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG CreateOptions,
_In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
_In_ ULONG EaLength) {
Unhook();
FuncPtr func = (FuncPtr)target;
NTSTATUS s = func(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
if (!wcscmp(ObjectAttributes->ObjectName->Buffer, L"\\??\\C:\\card.txt")) {
kprintf(("call NtCreateFile(%p,%p,%S,%p,%p,%p,%p,%p,%p,%p,%p)\n"), FileHandle,DesiredAccess,ObjectAttributes->ObjectName->Buffer,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
DbgBreakPoint();
FileHandler = *FileHandle;
}
//DbgBreakPoint();
Hook();
return s;
}
ULONG myReadFile(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_In_opt_ PLARGE_INTEGER ByteOffset,
_In_opt_ PULONG Key) {
Unhook2();
FuncPtr2 func = (FuncPtr2)target2;
if (FileHandler && FileHandler == FileHandle) {
kprintf(("call NtReadFile(%p,%p,%p,%p,%p,%p,%p,%p,%p)\n"), FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset, Key);
DbgBreakPoint();
FileHandler = 0;
}
//DbgBreakPoint();
NTSTATUS s = func(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,Buffer,Length,ByteOffset,Key);
Hook2();
return s;
}
void DriverUnload(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start unload\n"), __LINE__);
Unhook();
Unhook2();
DeleteDevice(pDriver);
}
NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath
) {
DriverObject->DriverUnload = DriverUnload;
kprintf(("Line %d:xia0ji233: RegistryPath = %S\n"), __LINE__, RegistryPath->Buffer);
target = NtCreateFile;
target2 = NtReadFile;
kprintf(("Line %d:xia0ji233: NtCreateFile=%p NtReadFile=%p\n"), __LINE__, target,target2);
g_Object = DriverObject;
if (target&&target2) {
for (int i = 0; i < sizeof(oldcode); i++) {
oldcode = target;
oldcode2 = target2;
}
*(UINT64*)(newcode + 2) = myCreateFile;
*(UINT64*)(newcode2 + 2) = myReadFile;
Hook();
Hook2();
}
else {
kprintf(("xia0ji233:hahaha"));
}
return 0;
}
```
跟到后面可以找到文件内容(ReadFile第六个参数),在文件内容处下硬件读取断点,可以找到这里文件内容被被写入两个寄存器,随后又写入另外的内存(RCX所指向的内存)。
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/1.png)
然后就直接 ret 了,这里将内存窗口转到 RCX 指向的地址,然后程序跳出来。
紧接着给末尾添 0 字节,然后将 r14 与 0x10 比较,小于跳出
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/2.png)
这一次输出失败了,于是考虑换长度但是改一个字符,发现在另外的位置写了零字节
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/3.png)
在跟的过程中,发现后面的一个内存就是长度
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/4.png)
然后接着跟,会跟到一个找 - 的代码
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/5.png)
很容易理解,因为 - 就是分隔 user 和 key 的,必然有一个遍历在找 - 的位置,那就直接跳到它找到了 - 的位置,发现有一个大跳转
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/6.png)
随后会把 - 所处的地址存入栈中
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/7.png)
紧接着跟,发现把User拷贝到下面的内存了
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/8.png)
随后将key也写入下方的内存
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/9.png)
然后开始循环 key,判断如果 -0x30 是否 >10,应该 key 只能是数字的判断。
于是我在循环这里下了一个软件断点,发现 RDI 会存储当前已遍历的十进制。
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/11.png)
例如现在已经遍历到了 405,那么 rdi=0x195=405。
经过数次的循环,
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/12.png)
可以发现 RDI=0xF17E203C,就是 4051574844,那么接下来就往下面跟看看跟 User 有什么样的关系。
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/13.png)
取出ACE之后算出一个值 0x0000000020450083,最后很 0x1003F 相乘,得到 00000000F17E203D,刚好是题目所给 key 的十六进制表示。
后面通过一定的调试分析,发现一个规律
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/14.png)
似乎它会把每一个字符加起来然后 `*0x1003F`,并且一定是 `int`。
先验证一遍ACE是否正确
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/15.png)
发现果然如此,那么照样子算出 key 为 `4007951923`。
#### 编写一个keygen,能生成对于任何用户名的KEY(1分)
根据上面的分析,不难写出 keygen 程序
```C
#include<stdio.h>
#include<string.h>
int main(){
char user[]="xia0ji233";
int n=strlen(user);
unsigned key=0;
for(int i=0;i<n;i++){
key=(key+user)*0x1003F;
}
printf("%u\n",key);
}
```
运行即可获得 key 的输出。
#### 编写一个exp,在exp程序运行后,对于任意的用户名-key,Loader.sys均能正确启动(1分)
有这么几种方法:监控内核线程,在 shellcode 执行的时候拦截,把比较是否相等的代码patch掉。监控文件读写,在读文件的时候,判断如果是目标文件,让它返回正确的结果。
最后还是选择在文件处拦截,然后趁它读文件的时候遍历驱动模块改它代码,上面分析的 imul 关键指令在 `Loader.sys+0xafc1c4` 的位置
再调试一遍,决出关键一步,找到了 cmp 指令
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/16.png)
如图所示的内存分别为实际输入的数值和通过 user 计算得到的key的数值,随后取出相比较,不相等显然跳转到 Fail 分支,因此这里改成 NOP 让它不跳转任意情况下跳转成功。
此时的 sys 基地址为 `0xFFFFF806F82D0000`,与该指令相减得到 `0xa27e` 的偏移,只需把这两个字节改成 0x90 即可达到任意的 user key 可以成功加载驱动。
我先使用了hook的方式去劫持,确保劫持的函数没错,再通过修改劫持时机和方式让方法满足要求
```C
#include <ntifs.h>
#include <ntdef.h>
#include <ntstatus.h>
#include <ntddk.h>
#define MAX_BACKTRACE_DEPTH 20
#define SYMBOL L"\\??\\xia0ji2333"
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)
UINT64 BaseAddr=NULL, DLLSize=0;
void DeleteDevice(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start delete device\n"), __LINE__);
if (pDriver->DeviceObject) {
UNICODE_STRING Sym;
RtlInitUnicodeString(&Sym, SYMBOL);//CreateFile
kprintf(("Line %d:xia0ji233: Delete Symbol\n"), __LINE__);
IoDeleteSymbolicLink(&Sym);
kprintf(("Line %d:xia0ji233: Delete Device\n"), __LINE__);
IoDeleteDevice(pDriver->DeviceObject);
}
kprintf(("Line %d:xia0ji233: end delete device\n"), __LINE__);
}
HANDLE FileHandler = NULL;
char newcode[] = {
0x48,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov rax,xxx
0xFF,0xE0//jmp rax
};
char oldcode[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
char newcode2[] = {
0x48,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov rax,xxx
0xFF,0xE0//jmp rax
};
char oldcode2[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
char* target;
char* target2;
KIRQL WPOFFx64()
{
KIRQL irql = KeRaiseIrqlToDpcLevel();
UINT64 cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
_disable();
return irql;
}
void WPONx64(KIRQL irql)
{
UINT64 cr0 = __readcr0();
cr0 |= 0x10000;
_enable();
__writecr0(cr0);
KeLowerIrql(irql);
}
NTSTATUS Unhook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target = oldcode;
}
WPONx64(irql);
return STATUS_SUCCESS;
}
NTSTATUS Unhook2() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode2); i++) {
target2 = oldcode2;
}
WPONx64(irql);
return STATUS_SUCCESS;
}
NTSTATUS Hook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target = newcode;
}
WPONx64(irql);
return STATUS_SUCCESS;
}
NTSTATUS Hook2() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode2); i++) {
target2 = newcode2;
}
WPONx64(irql);
return STATUS_SUCCESS;
}
PDRIVER_OBJECT g_Object = NULL;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;//驱动的进入点 DriverEntry
ULONG SizeOfImage;
UNICODE_STRING FullDllName;//驱动的满路径
UNICODE_STRING BaseDllName;//不带路径的驱动名字
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef NTSTATUS (* FuncPtr) (
_Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG CreateOptions,
_In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
_In_ ULONG EaLength
);
typedef NTSTATUS (* FuncPtr2 )(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_In_opt_ PLARGE_INTEGER ByteOffset,
_In_opt_ PULONG Key
);
NTSTATUS EnumerateKernelThreads();
typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved;
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
ULONG BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
typedef struct _SYSTEM_THREAD_INFORMATION {
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientId;
ULONG Priority;
LONG BasePriority;
ULONG ContextSwitchCount;
LONG State;
LONG WaitReason;
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemProcessInformation = 5
} SYSTEM_INFORMATION_CLASS;
#define SystemModuleInformation 11
ULONGmyCreateFile(_Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG CreateOptions,
_In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
_In_ ULONG EaLength) {
Unhook();
FuncPtr func = (FuncPtr)target;
NTSTATUS s = func(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
if (!wcscmp(ObjectAttributes->ObjectName->Buffer, L"\\??\\C:\\card.txt")) {
kprintf(("call NtCreateFile(%p,%p,%S,%p,%p,%p,%p,%p,%p,%p,%p)\n"), FileHandle,DesiredAccess,ObjectAttributes->ObjectName->Buffer,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
//DbgBreakPoint();
FileHandler = *FileHandle;
}
//DbgBreakPoint();
Hook();
return s;
}
MDLWriteMemory(PVOID pBaseAddress, PVOID pWriteData, SIZE_T writeDataSize)
{
PMDL pMdl = NULL;
PVOID pNewAddress = NULL;
pMdl = MmCreateMdl(NULL, pBaseAddress, writeDataSize);
if (NULL == pMdl)
{
return FALSE;
}
MmBuildMdlForNonPagedPool(pMdl);
pNewAddress = MmMapLockedPages(pMdl, KernelMode);
if (NULL == pNewAddress)
{
IoFreeMdl(pMdl);
}
RtlCopyMemory(pNewAddress, pWriteData, writeDataSize);
MmUnmapLockedPages(pNewAddress, pMdl);
IoFreeMdl(pMdl);
return TRUE;
}
VOID PatchInstr()
{
LDR_DATA_TABLE_ENTRY *TE, *Tmp;
TE = (LDR_DATA_TABLE_ENTRY*)g_Object->DriverSection;
PLIST_ENTRY LinkList;
;
int i = 0;
LinkList = TE->InLoadOrderLinks.Flink;
UNICODE_STRING name;
RtlInitUnicodeString(&name,L"Loader.sys");
;
while (LinkList != &TE->InLoadOrderLinks)
{
Tmp = (LDR_DATA_TABLE_ENTRY*)LinkList;
if (RtlEqualUnicodeString(&Tmp->BaseDllName, &name,FALSE)) {
kprintf(("DLLname:%S DLLBase=%p nowcode=%p\n"), Tmp->BaseDllName.Buffer,Tmp->DllBase,(ULONG64)(Tmp->DllBase) + 0xa27e);
char buffer[] = { 0x90,0x90 };
MDLWriteMemory((ULONG64)(Tmp->DllBase) + 0xa27e, buffer, 2);
return;
}
LinkList = LinkList->Flink;
i++;
}
}
ULONG myReadFile(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_In_opt_ PLARGE_INTEGER ByteOffset,
_In_opt_ PULONG Key) {
Unhook2();
FuncPtr2 func = (FuncPtr2)target2;
if (FileHandler && FileHandler == FileHandle) {
kprintf(("call NtReadFile(%p,%p,%p,%p,%p,%p,%p,%p,%p)\n"), FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset, Key);
kprintf(("buffer in %p\n"), Buffer);
PatchInstr();
FileHandler = 0;
}
//DbgBreakPoint();
NTSTATUS s = func(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,Buffer,Length,ByteOffset,Key);
Hook2();
return s;
}
void DriverUnload(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start unload\n"), __LINE__);
Unhook();
Unhook2();
DeleteDevice(pDriver);
}
NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath
) {
DriverObject->DriverUnload = DriverUnload;
kprintf(("Line %d:xia0ji233: RegistryPath = %S\n"), __LINE__, RegistryPath->Buffer);
target = NtCreateFile;
target2 = NtReadFile;
kprintf(("Line %d:xia0ji233: NtCreateFile=%p NtReadFile=%p\n"), __LINE__, target,target2);
g_Object = DriverObject;
if (target&&target2) {
for (int i = 0; i < sizeof(oldcode); i++) {
oldcode = target;
oldcode2 = target2;
}
*(UINT64*)(newcode + 2) = myCreateFile;
*(UINT64*)(newcode2 + 2) = myReadFile;
Hook();
Hook2();
}
else {
kprintf(("xia0ji233:hahaha"));
}
return 0;
}
int Filter(ULONG Start)
{
LDR_DATA_TABLE_ENTRY *TE, *Tmp;
TE = (LDR_DATA_TABLE_ENTRY*)g_Object->DriverSection;
PLIST_ENTRY LinkList;
;
int i = 0;
LinkList = TE->InLoadOrderLinks.Flink;
while (LinkList != &TE->InLoadOrderLinks)
{
Tmp = (LDR_DATA_TABLE_ENTRY*)LinkList;
ULONG BASE = Tmp->DllBase;
ULONG Size = Tmp->SizeOfImage;
if (Start >= BASE && Start < BASE + Size) {
return 0;
}
LinkList = LinkList->Flink;
i++;
}
return 1;
}
```
可以看到,先加载我写的驱动,后加载题目驱动,无论 user-key 正确与否,都加载成功
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/17.png)
于是这里把修改的函数套到文件读取里面去拦截,达到读该文件时遍历模块,找到指定模块则写入指令。
下面是真正的代码(编译文件为XSafe2.sys)
```C
#include <ntifs.h>
#include <ntdef.h>
#include <ntstatus.h>
#include <ntddk.h>
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)
typedef struct _CALLBACK_ENTRY
{
LIST_ENTRY CallbackList;
OB_OPERATIONOperations;
ULONG Active;
PVOID Handle;
POBJECT_TYPE ObjectType;
POB_PRE_OPERATION_CALLBACKPreOperation;
POB_POST_OPERATION_CALLBACK PostOperation;
ULONG unknown;
} CALLBACK_ENTRY, *PCALLBACK_ENTRY;
typedef struct _LDR_DATA // 24 elements, 0xE0 bytes (sizeof)
{
/*0x000*/ struct _LIST_ENTRY InLoadOrderLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x010*/ struct _LIST_ENTRY InMemoryOrderLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x020*/ struct _LIST_ENTRY InInitializationOrderLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x030*/ VOID* DllBase;
/*0x038*/ VOID* EntryPoint;
/*0x040*/ ULONG32 SizeOfImage;
/*0x044*/ UINT8 _PADDING0_;
/*0x048*/ struct _UNICODE_STRING FullDllName; // 3 elements, 0x10 bytes (sizeof)
/*0x058*/ struct _UNICODE_STRING BaseDllName; // 3 elements, 0x10 bytes (sizeof)
/*0x068*/ ULONG32 Flags;
/*0x06C*/ UINT16 LoadCount;
/*0x06E*/ UINT16 TlsIndex;
union // 2 elements, 0x10 bytes (sizeof)
{
/*0x070*/ struct _LIST_ENTRY HashLinks; // 2 elements, 0x10 bytes (sizeof)
struct // 2 elements, 0x10 bytes (sizeof)
{
/*0x070*/ VOID* SectionPointer;
/*0x078*/ ULONG32 CheckSum;
/*0x07C*/ UINT8 _PADDING1_;
};
};
union // 2 elements, 0x8 bytes (sizeof)
{
/*0x080*/ ULONG32 TimeDateStamp;
/*0x080*/ VOID* LoadedImports;
};
/*0x088*/ struct _ACTIVATION_CONTEXT* EntryPointActivationContext;
/*0x090*/ VOID* PatchInformation;
/*0x098*/ struct _LIST_ENTRY ForwarderLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x0A8*/ struct _LIST_ENTRY ServiceTagLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x0B8*/ struct _LIST_ENTRY StaticLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x0C8*/ VOID* ContextInformation;
/*0x0D0*/ UINT64 OriginalBase;
/*0x0D8*/ union _LARGE_INTEGER LoadTime; // 4 elements, 0x8 bytes (sizeof)
}LDR_DATA, *PLDR_DATA;
typedef struct _OBJECT_TYPE_INITIALIZER // 25 elements, 0x70 bytes (sizeof)
{
/*0x000*/ UINT16 Length;
union // 2 elements, 0x1 bytes (sizeof)
{
/*0x002*/ UINT8 ObjectTypeFlags;
struct // 7 elements, 0x1 bytes (sizeof)
{
/*0x002*/ UINT8 CaseInsensitive : 1; // 0 BitPosition
/*0x002*/ UINT8 UnnamedObjectsOnly : 1; // 1 BitPosition
/*0x002*/ UINT8 UseDefaultObject : 1; // 2 BitPosition
/*0x002*/ UINT8 SecurityRequired : 1; // 3 BitPosition
/*0x002*/ UINT8 MaintainHandleCount : 1; // 4 BitPosition
/*0x002*/ UINT8 MaintainTypeList : 1; // 5 BitPosition
/*0x002*/ UINT8 SupportsObjectCallbacks : 1; // 6 BitPosition
};
};
/*0x004*/ ULONG32 ObjectTypeCode;
/*0x008*/ ULONG32 InvalidAttributes;
/*0x00C*/ struct _GENERIC_MAPPING GenericMapping; // 4 elements, 0x10 bytes (sizeof)
/*0x01C*/ ULONG32 ValidAccessMask;
/*0x020*/ ULONG32 RetainAccess;
/*0x024*/ enum _POOL_TYPE PoolType;
/*0x028*/ ULONG32 DefaultPagedPoolCharge;
/*0x02C*/ ULONG32 DefaultNonPagedPoolCharge;
/*0x030*/ PVOID DumpProcedure;
/*0x038*/ PVOID OpenProcedure;
/*0x040*/ PVOID CloseProcedure;
/*0x048*/ PVOID DeleteProcedure;
/*0x050*/ PVOID ParseProcedure;
/*0x058*/ PVOID SecurityProcedure;
/*0x060*/ PVOID QueryNameProcedure;
/*0x068*/ PVOID OkayToCloseProcedure;
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
typedef struct _EX_PUSH_LOCK // 7 elements, 0x8 bytes (sizeof)
{
union // 3 elements, 0x8 bytes (sizeof)
{
struct // 5 elements, 0x8 bytes (sizeof)
{
/*0x000*/ UINT64 Locked : 1; // 0 BitPosition
/*0x000*/ UINT64 Waiting : 1; // 1 BitPosition
/*0x000*/ UINT64 Waking : 1; // 2 BitPosition
/*0x000*/ UINT64 MultipleShared : 1; // 3 BitPosition
/*0x000*/ UINT64 Shared : 60; // 4 BitPosition
};
/*0x000*/ UINT64 Value;
/*0x000*/ VOID* Ptr;
};
};
typedef struct _MY_OBJECT_TYPE // 12 elements, 0xD0 bytes (sizeof)
{
/*0x000*/ struct _LIST_ENTRY TypeList; // 2 elements, 0x10 bytes (sizeof)
/*0x010*/ struct _UNICODE_STRING Name; // 3 elements, 0x10 bytes (sizeof)
/*0x020*/ VOID* DefaultObject;
/*0x028*/ UINT8 Index;
/*0x029*/ UINT8 _PADDING0_;
/*0x02C*/ ULONG32 TotalNumberOfObjects;
/*0x030*/ ULONG32 TotalNumberOfHandles;
/*0x034*/ ULONG32 HighWaterNumberOfObjects;
/*0x038*/ ULONG32 HighWaterNumberOfHandles;
/*0x03C*/ UINT8 _PADDING1_;
/*0x040*/ struct _OBJECT_TYPE_INITIALIZER TypeInfo; // 25 elements, 0x70 bytes (sizeof)
/*0x0B0*/ struct _EX_PUSH_LOCK TypeLock; // 7 elements, 0x8 bytes (sizeof)
/*0x0B8*/ ULONG32 Key;
/*0x0BC*/ UINT8 _PADDING2_;
/*0x0C0*/ struct _LIST_ENTRY CallbackList; // 2 elements, 0x10 bytes (sizeof)
}MY_OBJECT_TYPE, *PMY_OBJECT_TYPE;
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
VOID UnloadDriver(PDRIVER_OBJECT DriverObject);
NTSTATUS EnumerateKernelThreads();
typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved;
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
ULONG BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
typedef struct _SYSTEM_THREAD_INFORMATION {
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientId;
ULONG Priority;
LONG BasePriority;
ULONG ContextSwitchCount;
LONG State;
LONG WaitReason;
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemProcessInformation = 5
} SYSTEM_INFORMATION_CLASS;
#define SystemModuleInformation 11
PVOID obHandle;
DRIVER_INITIALIZE DriverEntry;
PDRIVER_OBJECT g_Object = NULL;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;//驱动的进入点 DriverEntry
ULONG SizeOfImage;
UNICODE_STRING FullDllName;//驱动的满路径
UNICODE_STRING BaseDllName;//不带路径的驱动名字
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
MDLWriteMemory(PVOID pBaseAddress, PVOID pWriteData, SIZE_T writeDataSize)
{
PMDL pMdl = NULL;
PVOID pNewAddress = NULL;
pMdl = MmCreateMdl(NULL, pBaseAddress, writeDataSize);
if (NULL == pMdl)
{
return FALSE;
}
MmBuildMdlForNonPagedPool(pMdl);
pNewAddress = MmMapLockedPages(pMdl, KernelMode);
if (NULL == pNewAddress)
{
IoFreeMdl(pMdl);
}
RtlCopyMemory(pNewAddress, pWriteData, writeDataSize);
MmUnmapLockedPages(pNewAddress, pMdl);
IoFreeMdl(pMdl);
return TRUE;
}
VOID PatchInstr()
{
LDR_DATA_TABLE_ENTRY *TE, *Tmp;
TE = (LDR_DATA_TABLE_ENTRY*)g_Object->DriverSection;
PLIST_ENTRY LinkList;
;
int i = 0;
LinkList = TE->InLoadOrderLinks.Flink;
UNICODE_STRING name;
RtlInitUnicodeString(&name,L"Loader.sys");
;
while (LinkList != &TE->InLoadOrderLinks)
{
Tmp = (LDR_DATA_TABLE_ENTRY*)LinkList;
if (RtlEqualUnicodeString(&Tmp->BaseDllName, &name,FALSE)) {
kprintf(("DLLname:%S DLLBase=%p nowcode=%p\n"), Tmp->BaseDllName.Buffer,Tmp->DllBase,(ULONG64)(Tmp->DllBase) + 0xa27e);
char buffer[] = { 0x90,0x90 };
MDLWriteMemory((ULONG64)(Tmp->DllBase) + 0xa27e, buffer, 2);
return;
}
LinkList = LinkList->Flink;
i++;
}
}
// 文件回调
OB_PREOP_CALLBACK_STATUS FileObjectpreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
{
UNICODE_STRING DosName;
PFILE_OBJECT fileo = OperationInformation->Object;
HANDLE CurrentProcessId = PsGetCurrentProcessId();
UNREFERENCED_PARAMETER(RegistrationContext);
if (OperationInformation->ObjectType != *IoFileObjectType)
{
return OB_PREOP_SUCCESS;
}
// 过滤无效指针
if (fileo->FileName.Buffer == NULL ||
!MmIsAddressValid(fileo->FileName.Buffer) ||
fileo->DeviceObject == NULL ||
!MmIsAddressValid(fileo->DeviceObject))
{
return OB_PREOP_SUCCESS;
}
// 过滤无效路径
if (!_wcsicmp(fileo->FileName.Buffer, L"\\Endpoint") ||
!_wcsicmp(fileo->FileName.Buffer, L"?") ||
!_wcsicmp(fileo->FileName.Buffer, L"\\.\\.") ||
!_wcsicmp(fileo->FileName.Buffer, L"\\"))
{
return OB_PREOP_SUCCESS;
}
// 将对象转为DOS路径
RtlVolumeDeviceToDosName(fileo->DeviceObject, &DosName);
if (!wcscmp(fileo->FileName.Buffer, L"\\card.txt")) {
PETHREAD pct=PsGetCurrentThread();
PVOID addr=*(ULONG64*)((char*)pct + 0x450);
PatchInstr();
//EnumerateKernelThreads();
DbgBreakPoint();
}
return OB_PREOP_SUCCESS;
}
VOID EnableObType(POBJECT_TYPE ObjectType)
{
PMY_OBJECT_TYPE myobtype = (PMY_OBJECT_TYPE)ObjectType;
myobtype->TypeInfo.SupportsObjectCallbacks = 1;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
UNREFERENCED_PARAMETER(driver);
ObUnRegisterCallbacks(obHandle);
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
PLDR_DATA ldr;
kprintf(("hello xia0ji233\n"));
g_Object = Driver;
OB_CALLBACK_REGISTRATION obRegFileCallBack;
OB_OPERATION_REGISTRATION opRegFileCallBack;
// enable IoFileObjectType
EnableObType(*IoFileObjectType);
// bypass MmVerifyCallbackFunction
ldr = (PLDR_DATA)Driver->DriverSection;
ldr->Flags |= 0x20;
// 初始化回调
memset(&obRegFileCallBack, 0, sizeof(obRegFileCallBack));
obRegFileCallBack.Version = ObGetFilterVersion();
obRegFileCallBack.OperationRegistrationCount = 1;
obRegFileCallBack.RegistrationContext = NULL;
RtlInitUnicodeString(&obRegFileCallBack.Altitude, L"321000");
obRegFileCallBack.OperationRegistration = &opRegFileCallBack;
memset(&opRegFileCallBack, 0, sizeof(opRegFileCallBack));
opRegFileCallBack.ObjectType = IoFileObjectType;
opRegFileCallBack.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
opRegFileCallBack.PreOperation = (POB_PRE_OPERATION_CALLBACK)&FileObjectpreCall;
status = ObRegisterCallbacks(&obRegFileCallBack, &obHandle);
if (!NT_SUCCESS(status))
{
kprintf(("注册回调错误 \n"));
status = STATUS_UNSUCCESSFUL;
}
UNREFERENCED_PARAMETER(RegistryPath);
Driver->DriverUnload = &UnDriver;
return status;
}
```
该程序(附件中的XSafe2.sys)先加载,再加载Loader.sys同样可以任意user key加载成功并且不hook任何系统API和文件。
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/18.png)
#### 分析shellcode反复在读取哪个内存地址(2分)
shellcode加载之后,会检测双机调试
但是有一定的延迟,说明是主动检测的不是被动触发的,刚好遇上这个题,猜测是检测了一个调试器标志位。
不过这里感觉是得先确定一下 shellcode 的位置的,因为它带反调,不知道它怎么反调的,突然想到之前一位神仙把蓝屏代码删了导致电脑爆炸,于是我也想效仿一下看看可不可彳亍。
```C
#include <ntifs.h>
#include <ntdef.h>
#include <ntstatus.h>
#include <ntddk.h>
#define MAX_BACKTRACE_DEPTH 20
#define SYMBOL L"\\??\\xia0ji2333"
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)
UINT64 BaseAddr=NULL, DLLSize=0;
#define MAX_BACKTRACE_DEPTH 20
void DeleteDevice(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start delete device\n"), __LINE__);
if (pDriver->DeviceObject) {
UNICODE_STRING Sym;
RtlInitUnicodeString(&Sym, SYMBOL);//CreateFile
kprintf(("Line %d:xia0ji233: Delete Symbol\n"), __LINE__);
IoDeleteSymbolicLink(&Sym);
kprintf(("Line %d:xia0ji233: Delete Device\n"), __LINE__);
IoDeleteDevice(pDriver->DeviceObject);
}
kprintf(("Line %d:xia0ji233: end delete device\n"), __LINE__);
}
HANDLE FileHandler = NULL;
char newcode[] = {
0x48,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov rax,xxx
0xFF,0xE0//jmp rax
};
char oldcode[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
char* target;
KIRQL WPOFFx64()
{
KIRQL irql = KeRaiseIrqlToDpcLevel();
UINT64 cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
_disable();
return irql;
}
void WPONx64(KIRQL irql)
{
UINT64 cr0 = __readcr0();
cr0 |= 0x10000;
_enable();
__writecr0(cr0);
KeLowerIrql(irql);
}
NTSTATUS Unhook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target = oldcode;
}
WPONx64(irql);
return STATUS_SUCCESS;
}
NTSTATUS Hook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target = newcode;
}
WPONx64(irql);
return STATUS_SUCCESS;
}
PDRIVER_OBJECT g_Object = NULL;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;//驱动的进入点 DriverEntry
ULONG SizeOfImage;
UNICODE_STRING FullDllName;//驱动的满路径
UNICODE_STRING BaseDllName;//不带路径的驱动名字
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef NTSTATUS (* FuncPtr) (
_In_ ULONG BugCheckCode,
_In_ ULONG_PTR BugCheckParameter1,
_In_ ULONG_PTR BugCheckParameter2,
_In_ ULONG_PTR BugCheckParameter3,
_In_ ULONG_PTR BugCheckParameter4
);
ULONGmyKeBugCheckEx(_In_ ULONG BugCheckCode,
_In_ ULONG_PTR BugCheckParameter1,
_In_ ULONG_PTR BugCheckParameter2,
_In_ ULONG_PTR BugCheckParameter3,
_In_ ULONG_PTR BugCheckParameter4
) {
Unhook();
FuncPtr func = (FuncPtr)target;
PVOID backtrace;
USHORT capturedFrames = RtlCaptureStackBackTrace(0, MAX_BACKTRACE_DEPTH, backtrace, NULL);
for (USHORT i = 0; i < capturedFrames; i++) {
kprintf(("xia0ji233:Backtrace[%u]: %p\n"), i, backtrace);
}
kprintf(("calling KeBugCheckEx(%p,%p,%p,%p,%p)\n"),BugCheckCode,BugCheckParameter1,BugCheckParameter2,BugCheckParameter3,BugCheckParameter4);
DbgBreakPoint();
LARGE_INTEGER inTime;
inTime.QuadPart = (LONGLONG) - 10 * 1000 * 1000 * 3600;
KeDelayExecutionThread(KernelMode, FALSE, &inTime);
ULONG64 s = func(BugCheckCode,BugCheckParameter1,BugCheckParameter2,BugCheckParameter3,BugCheckParameter4);
Hook();
return s;
}
MDLWriteMemory(PVOID pBaseAddress, PVOID pWriteData, SIZE_T writeDataSize)
{
PMDL pMdl = NULL;
PVOID pNewAddress = NULL;
pMdl = MmCreateMdl(NULL, pBaseAddress, writeDataSize);
if (NULL == pMdl)
{
return FALSE;
}
MmBuildMdlForNonPagedPool(pMdl);
pNewAddress = MmMapLockedPages(pMdl, KernelMode);
if (NULL == pNewAddress)
{
IoFreeMdl(pMdl);
}
RtlCopyMemory(pNewAddress, pWriteData, writeDataSize);
MmUnmapLockedPages(pNewAddress, pMdl);
IoFreeMdl(pMdl);
return TRUE;
}
void DriverUnload(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start unload\n"), __LINE__);
Unhook();
DeleteDevice(pDriver);
}
NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath
) {
DriverObject->DriverUnload = DriverUnload;
kprintf(("Line %d:xia0ji233: RegistryPath = %S\n"), __LINE__, RegistryPath->Buffer);
UNICODE_STRING unName = { 0 };
RtlInitUnicodeString(&unName, L"KeBugCheckEx");
target = ((ULONG64)MmGetSystemRoutineAddress(&unName))+5;
kprintf(("Line %d:xia0ji233: KeBugCheckEx=%p\n"), __LINE__, target);
g_Object = DriverObject;
if (target) {
for (int i = 0; i < sizeof(oldcode); i++) {
oldcode = target;
}
*(UINT64*)(newcode + 2) = myKeBugCheckEx;
Hook();
}
else {
kprintf(("xia0ji233:hahaha"));
}
return 0;
}
```
这里去hook KeBugCheckEx,然后直接让它 sleep 一小时,防止它蓝我,我有更多时间可以去分析。
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/19.png)
直接拿捏住了蓝屏。
在后面的分析中发现了 GameSec.exe 的内存一直在被读,估计是在搜索进程,然后读取进程的内存,这一部分后面没有分析太出来。
并且在运行的时候发现会读一些 exe 文件的字符串,在 shellcode 开头 + 80 的位置,这里后续没继续分析了。
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/2_1.png)
#### 编写一个search程序,在Load驱动运行后找到内核内存空间中的shellcode,输出shellcode范围内的任意地址
随后想到去dump shellcode,这里注册回调的方式并不能成功拦截住,因此想到直接去 hook,判断线程起始位置是否在模块范围内,或者说在 Loader.sys 范围内,如果有都输出然后调试器看看内存像不像shellcode,无果,于是选择去跟一下,结果跟到一个类似shellcode的地方(很多浮点指令,看起来像垃圾指令的混淆),dump下来用 010 分析。
##### 方法1
通过内存地址的特征可以发现,前八位可以通过 VAD 的方式去获取,后四个位每次加载似乎都是固定的,因此只需要爆破两个字节用一个特征去匹配就行了,这里。
```C
#include "vad.h"
#include <ntifs.h>
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)
// 定义VAD相对于EProcess头部偏移值
#define eprocess_offset_VadRoot 0x658
#define eprocess_offset_VadCount 0x668
VOID EnumVad(PMMVAD Root, PALL_VADS pBuffer, ULONG nCnt)
{
if (!Root || !pBuffer || !nCnt)
{
return;
}
__try
{
if (nCnt > pBuffer->nCnt)
{
// 得到起始页与结束页
ULONG64 endptr = (ULONG64)Root->Core.EndingVpnHigh;
endptr = endptr << 32;
ULONG64 startptr = (ULONG64)Root->Core.StartingVpnHigh;
startptr = startptr << 32;
// 得到根节点
pBuffer->VadInfos.pVad = (ULONG_PTR)Root;
// 起始页: startingVpn * 0x1000
pBuffer->VadInfos.startVpn = (startptr | Root->Core.StartingVpn) << PAGE_SHIFT;
// 结束页: EndVpn * 0x1000 + 0xfff
pBuffer->VadInfos.endVpn = ((endptr | Root->Core.EndingVpn) << PAGE_SHIFT) + 0xfff;
// VAD标志 928 = Mapped 1049088 = Private ....
pBuffer->VadInfos.flags = Root->Core.u1.Flags.flag;
// 验证节点可读性
if (MmIsAddressValid(Root->Subsection) && MmIsAddressValid(Root->Subsection->ControlArea))
{
if (MmIsAddressValid((PVOID)((Root->Subsection->ControlArea->FilePointer.Value >> 4) << 4)))
{
pBuffer->VadInfos.pFileObject = ((Root->Subsection->ControlArea->FilePointer.Value >> 4) << 4);
}
}
pBuffer->nCnt++;
}
if (MmIsAddressValid(Root->Core.VadNode.Left))
{
// 递归枚举左子树
EnumVad((PMMVAD)Root->Core.VadNode.Left, pBuffer, nCnt);
}
if (MmIsAddressValid(Root->Core.VadNode.Right))
{
// 递归枚举右子树
EnumVad((PMMVAD)Root->Core.VadNode.Right, pBuffer, nCnt);
}
}
__except (1)
{
}
}
BOOLEAN EnumProcessVad(ULONG Pid, PALL_VADS pBuffer, ULONG nCnt)
{
PEPROCESS Peprocess = 0;
PRTL_AVL_TREE Table = NULL;
PMMVAD Root = NULL;
// 通过进程PID得到进程EProcess
if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)Pid, &Peprocess)))
{
// 与偏移相加得到VAD头节点
Table = (PRTL_AVL_TREE)((UCHAR*)Peprocess + eprocess_offset_VadRoot);
if (!MmIsAddressValid(Table) || !eprocess_offset_VadRoot)
{
return FALSE;
}
__try
{
// 取出头节点
Root = (PMMVAD)Table->Root;
if (nCnt > pBuffer->nCnt)
{
// 得到起始页与结束页
ULONG64 endptr = (ULONG64)Root->Core.EndingVpnHigh;
endptr = endptr << 32;
ULONG64 startptr = (ULONG64)Root->Core.StartingVpnHigh;
startptr = startptr << 32;
pBuffer->VadInfos.pVad = (ULONG_PTR)Root;
// 起始页: startingVpn * 0x1000
pBuffer->VadInfos.startVpn = (startptr | Root->Core.StartingVpn) << PAGE_SHIFT;
// 结束页: EndVpn * 0x1000 + 0xfff
pBuffer->VadInfos.endVpn = (endptr | Root->Core.EndingVpn) << PAGE_SHIFT;
pBuffer->VadInfos.flags = Root->Core.u1.Flags.flag;
if (MmIsAddressValid(Root->Subsection) && MmIsAddressValid(Root->Subsection->ControlArea))
{
if (MmIsAddressValid((PVOID)((Root->Subsection->ControlArea->FilePointer.Value >> 4) << 4)))
{
pBuffer->VadInfos.pFileObject = ((Root->Subsection->ControlArea->FilePointer.Value >> 4) << 4);
}
}
pBuffer->nCnt++;
}
// 枚举左子树
if (Table->Root->Left)
{
EnumVad((MMVAD*)Table->Root->Left, pBuffer, nCnt);
}
// 枚举右子树
if (Table->Root->Right)
{
EnumVad((MMVAD*)Table->Root->Right, pBuffer, nCnt);
}
}
__finally
{
ObDereferenceObject(Peprocess);
}
}
else
{
return FALSE;
}
return TRUE;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
kprintf(("unload\n"));
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
kprintf(("hello xia0ji233\n"));
typedef struct
{
ULONG nPid;
ULONG nSize;
PALL_VADS pBuffer;
}VADProcess;
__try
{
VADProcess vad = { 0 };
vad.nPid = 4;
// 默认有1000个线程
vad.nSize = sizeof(VAD_INFO) * 0x5000 + sizeof(ULONG);
// 分配临时空间
vad.pBuffer = (PALL_VADS)ExAllocatePool(PagedPool, vad.nSize);
// 根据传入长度得到枚举数量
ULONG nCount = (vad.nSize - sizeof(ULONG)) / sizeof(VAD_INFO);
// 枚举VAD
EnumProcessVad(vad.nPid, vad.pBuffer, nCount);
uintptr_t addr;
for (ULONG64 i = 0x0; i <65536; i++)
{
addr = vad.pBuffer->VadInfos.pVad & 0xffffffff00000000;
addr = addr + 0x1000;
addr = addr + (i<<16);
if (MmIsAddressValid((PVOID)addr) && *((ULONG64 *)addr) == 0x7C8B483024748B48 )
{
kprintf(("shellcode found in %p\n"), addr);
//DbgBreakPoint();
goto end;
}
}
}
__except (1)
{
kprintf(("Something Error1\n"));
}
end:
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
```
vad.h
```C
#pragma once
#include <ntifs.h>
typedef struct _MM_GRAPHICS_VAD_FLAGS // 15 elements, 0x4 bytes (sizeof)
{
/*0x000*/ ULONG32 Lock : 1; // 0 BitPosition
/*0x000*/ ULONG32 LockContended : 1; // 1 BitPosition
/*0x000*/ ULONG32 DeleteInProgress : 1; // 2 BitPosition
/*0x000*/ ULONG32 NoChange : 1; // 3 BitPosition
/*0x000*/ ULONG32 VadType : 3; // 4 BitPosition
/*0x000*/ ULONG32 Protection : 5; // 7 BitPosition
/*0x000*/ ULONG32 PreferredNode : 6; // 12 BitPosition
/*0x000*/ ULONG32 PageSize : 2; // 18 BitPosition
/*0x000*/ ULONG32 PrivateMemoryAlwaysSet : 1; // 20 BitPosition
/*0x000*/ ULONG32 WriteWatch : 1; // 21 BitPosition
/*0x000*/ ULONG32 FixedLargePageSize : 1; // 22 BitPosition
/*0x000*/ ULONG32 ZeroFillPagesOptional : 1;// 23 BitPosition
/*0x000*/ ULONG32 GraphicsAlwaysSet : 1; // 24 BitPosition
/*0x000*/ ULONG32 GraphicsUseCoherentBus : 1; // 25 BitPosition
/*0x000*/ ULONG32 GraphicsPageProtection : 3; // 26 BitPosition
}MM_GRAPHICS_VAD_FLAGS, * PMM_GRAPHICS_VAD_FLAGS;
typedef struct _MM_PRIVATE_VAD_FLAGS // 15 elements, 0x4 bytes (sizeof)
{
/*0x000*/ ULONG32 Lock : 1; // 0 BitPosition
/*0x000*/ ULONG32 LockContended : 1; // 1 BitPosition
/*0x000*/ ULONG32 DeleteInProgress : 1; // 2 BitPosition
/*0x000*/ ULONG32 NoChange : 1; // 3 BitPosition
/*0x000*/ ULONG32 VadType : 3; // 4 BitPosition
/*0x000*/ ULONG32 Protection : 5; // 7 BitPosition
/*0x000*/ ULONG32 PreferredNode : 6; // 12 BitPosition
/*0x000*/ ULONG32 PageSize : 2; // 18 BitPosition
/*0x000*/ ULONG32 PrivateMemoryAlwaysSet : 1; // 20 BitPosition
/*0x000*/ ULONG32 WriteWatch : 1; // 21 BitPosition
/*0x000*/ ULONG32 FixedLargePageSize : 1; // 22 BitPosition
/*0x000*/ ULONG32 ZeroFillPagesOptional : 1;// 23 BitPosition
/*0x000*/ ULONG32 Graphics : 1; // 24 BitPosition
/*0x000*/ ULONG32 Enclave : 1; // 25 BitPosition
/*0x000*/ ULONG32 ShadowStack : 1; // 26 BitPosition
}MM_PRIVATE_VAD_FLAGS, * PMM_PRIVATE_VAD_FLAGS;
typedef struct _MMVAD_FLAGS // 9 elements, 0x4 bytes (sizeof)
{
/*0x000*/ ULONG32 Lock : 1; // 0 BitPosition
/*0x000*/ ULONG32 LockContended : 1; // 1 BitPosition
/*0x000*/ ULONG32 DeleteInProgress : 1; // 2 BitPosition
/*0x000*/ ULONG32 NoChange : 1; // 3 BitPosition
/*0x000*/ ULONG32 VadType : 3; // 4 BitPosition
/*0x000*/ ULONG32 Protection : 5; // 7 BitPosition
/*0x000*/ ULONG32 PreferredNode : 6; // 12 BitPosition
/*0x000*/ ULONG32 PageSize : 2; // 18 BitPosition
/*0x000*/ ULONG32 PrivateMemory : 1; // 20 BitPosition
}MMVAD_FLAGS, * PMMVAD_FLAGS;
typedef struct _MM_SHARED_VAD_FLAGS // 11 elements, 0x4 bytes (sizeof)
{
/*0x000*/ ULONG32 Lock : 1; // 0 BitPosition
/*0x000*/ ULONG32 LockContended : 1; // 1 BitPosition
/*0x000*/ ULONG32 DeleteInProgress : 1; // 2 BitPosition
/*0x000*/ ULONG32 NoChange : 1; // 3 BitPosition
/*0x000*/ ULONG32 VadType : 3; // 4 BitPosition
/*0x000*/ ULONG32 Protection : 5; // 7 BitPosition
/*0x000*/ ULONG32 PreferredNode : 6; // 12 BitPosition
/*0x000*/ ULONG32 PageSize : 2; // 18 BitPosition
/*0x000*/ ULONG32 PrivateMemoryAlwaysClear : 1; // 20 BitPosition
/*0x000*/ ULONG32 PrivateFixup : 1; // 21 BitPosition
/*0x000*/ ULONG32 HotPatchAllowed : 1; // 22 BitPosition
}MM_SHARED_VAD_FLAGS, * PMM_SHARED_VAD_FLAGS;
typedef struct _MMVAD_FLAGS2 // 7 elements, 0x4 bytes (sizeof)
{
/*0x000*/ ULONG32 FileOffset : 24; // 0 BitPosition
/*0x000*/ ULONG32 Large : 1; // 24 BitPosition
/*0x000*/ ULONG32 TrimBehind : 1; // 25 BitPosition
/*0x000*/ ULONG32 Inherit : 1; // 26 BitPosition
/*0x000*/ ULONG32 NoValidationNeeded : 1; // 27 BitPosition
/*0x000*/ ULONG32 PrivateDemandZero : 1;// 28 BitPosition
/*0x000*/ ULONG32 Spare : 3; // 29 BitPosition
}MMVAD_FLAGS2, * PMMVAD_FLAGS2;
typedef struct _MMVAD_SHORT
{
RTL_BALANCED_NODE VadNode;
UINT32 StartingVpn; /*0x18*/
UINT32 EndingVpn; /*0x01C*/
UCHAR StartingVpnHigh;
UCHAR EndingVpnHigh;
UCHAR CommitChargeHigh;
UCHAR SpareNT64VadUChar;
INT32 ReferenceCount;
EX_PUSH_LOCK PushLock; /*0x028*/
struct
{
union
{
ULONG_PTR flag;
MM_PRIVATE_VAD_FLAGS PrivateVadFlags; /*0x030*/
MMVAD_FLAGSVadFlags;
MM_GRAPHICS_VAD_FLAGS GraphicsVadFlags;
MM_SHARED_VAD_FLAGS SharedVadFlags;
}Flags;
}u1;
PVOID EventList; /*0x038*/
}MMVAD_SHORT, * PMMVAD_SHORT;
typedef struct _MMADDRESS_NODE
{
ULONG64 u1;
struct _MMADDRESS_NODE* LeftChild;
struct _MMADDRESS_NODE* RightChild;
ULONG64 StartingVpn;
ULONG64 EndingVpn;
}MMADDRESS_NODE, * PMMADDRESS_NODE;
typedef struct _MMEXTEND_INFO // 2 elements, 0x10 bytes (sizeof)
{
/*0x000*/ UINT64 CommittedSize;
/*0x008*/ ULONG32 ReferenceCount;
/*0x00C*/ UINT8 _PADDING0_;
}MMEXTEND_INFO, * PMMEXTEND_INFO;
struct _SEGMENT
{
struct _CONTROL_AREA* ControlArea;
ULONG TotalNumberOfPtes;
ULONG SegmentFlags;
ULONG64 NumberOfCommittedPages;
ULONG64 SizeOfSegment;
union
{
struct _MMEXTEND_INFO* ExtendInfo;
void* BasedAddress;
}u;
ULONG64 SegmentLock;
ULONG64 u1;
ULONG64 u2;
PVOID* PrototypePte;
ULONGLONG ThePtes;
};
typedef struct _EX_FAST_REF
{
union
{
PVOID Object;
ULONG_PTR RefCnt : 3;
ULONG_PTR Value;
};
} EX_FAST_REF, * PEX_FAST_REF;
typedef struct _CONTROL_AREA // 17 elements, 0x80 bytes (sizeof)
{
/*0x000*/ struct _SEGMENT* Segment;
union // 2 elements, 0x10 bytes (sizeof)
{
/*0x008*/ struct _LIST_ENTRY ListHead; // 2 elements, 0x10 bytes (sizeof)
/*0x008*/ VOID* AweContext;
};
/*0x018*/ UINT64 NumberOfSectionReferences;
/*0x020*/ UINT64 NumberOfPfnReferences;
/*0x028*/ UINT64 NumberOfMappedViews;
/*0x030*/ UINT64 NumberOfUserReferences;
/*0x038*/ ULONG32 u; // 2 elements, 0x4 bytes (sizeof)
/*0x03C*/ ULONG32 u1; // 2 elements, 0x4 bytes (sizeof)
/*0x040*/ struct _EX_FAST_REF FilePointer; // 3 elements, 0x8 bytes (sizeof)
// 4 elements, 0x8 bytes (sizeof)
}CONTROL_AREA, * PCONTROL_AREA;
typedef struct _SUBSECTION_
{
struct _CONTROL_AREA* ControlArea;
}SUBSECTION, * PSUBSECTION;
typedef struct _MMVAD
{
MMVAD_SHORT Core;
union /*0x040*/
{
UINT32 LongFlags2;
//现在用不到省略
MMVAD_FLAGS2 VadFlags2;
}u2;
PSUBSECTION Subsection; /*0x048*/
PVOID FirstPrototypePte; /*0x050*/
PVOID LastContiguousPte; /*0x058*/
LIST_ENTRY ViewLinks; /*0x060*/
PEPROCESS VadsProcess; /*0x070*/
PVOID u4; /*0x078*/
PVOID FileObject; /*0x080*/
}MMVAD, * PMMVAD;
typedef struct _RTL_AVL_TREE // 1 elements, 0x8 bytes (sizeof)
{
/*0x000*/ struct _RTL_BALANCED_NODE* Root;
}RTL_AVL_TREE, * PRTL_AVL_TREE;
typedef struct _VAD_INFO_
{
ULONG_PTR pVad;
ULONG_PTR startVpn;
ULONG_PTR endVpn;
ULONG_PTR pFileObject;
ULONG_PTR flags;
}VAD_INFO, * PVAD_INFO;
typedef struct _ALL_VADS_
{
ULONG nCnt;
VAD_INFO VadInfos;
}ALL_VADS, * PALL_VADS;
typedef struct _MMSECTION_FLAGS // 27 elements, 0x4 bytes (sizeof)
{
/*0x000*/ UINT32 BeingDeleted : 1; // 0 BitPosition
/*0x000*/ UINT32 BeingCreated : 1; // 1 BitPosition
/*0x000*/ UINT32 BeingPurged : 1; // 2 BitPosition
/*0x000*/ UINT32 NoModifiedWriting : 1; // 3 BitPosition
/*0x000*/ UINT32 FailAllIo : 1; // 4 BitPosition
/*0x000*/ UINT32 Image : 1; // 5 BitPosition
/*0x000*/ UINT32 Based : 1; // 6 BitPosition
/*0x000*/ UINT32 File : 1; // 7 BitPosition
/*0x000*/ UINT32 AttemptingDelete : 1; // 8 BitPosition
/*0x000*/ UINT32 PrefetchCreated : 1; // 9 BitPosition
/*0x000*/ UINT32 PhysicalMemory : 1; // 10 BitPosition
/*0x000*/ UINT32 ImageControlAreaOnRemovableMedia : 1; // 11 BitPosition
/*0x000*/ UINT32 Reserve : 1; // 12 BitPosition
/*0x000*/ UINT32 Commit : 1; // 13 BitPosition
/*0x000*/ UINT32 NoChange : 1; // 14 BitPosition
/*0x000*/ UINT32 WasPurged : 1; // 15 BitPosition
/*0x000*/ UINT32 UserReference : 1; // 16 BitPosition
/*0x000*/ UINT32 GlobalMemory : 1; // 17 BitPosition
/*0x000*/ UINT32 DeleteOnClose : 1; // 18 BitPosition
/*0x000*/ UINT32 FilePointerNull : 1; // 19 BitPosition
/*0x000*/ ULONG32 PreferredNode : 6; // 20 BitPosition
/*0x000*/ UINT32 GlobalOnlyPerSession : 1; // 26 BitPosition
/*0x000*/ UINT32 UserWritable : 1; // 27 BitPosition
/*0x000*/ UINT32 SystemVaAllocated : 1; // 28 BitPosition
/*0x000*/ UINT32 PreferredFsCompressionBoundary : 1; // 29 BitPosition
/*0x000*/ UINT32 UsingFileExtents : 1; // 30 BitPosition
/*0x000*/ UINT32 PageSize64K : 1; // 31 BitPosition
}MMSECTION_FLAGS, * PMMSECTION_FLAGS;
typedef struct _SECTION // 9 elements, 0x40 bytes (sizeof)
{
/*0x000*/ struct _RTL_BALANCED_NODE SectionNode; // 6 elements, 0x18 bytes (sizeof)
/*0x018*/ UINT64 StartingVpn;
/*0x020*/ UINT64 EndingVpn;
/*0x028*/ union {
PCONTROL_AREA ControlArea;
PVOID FileObject;
}u1; // 4 elements, 0x8 bytes (sizeof)
/*0x030*/ UINT64 SizeOfSection;
/*0x038*/ union {
ULONG32 LongFlags;
MMSECTION_FLAGS Flags;
}u; // 2 elements, 0x4 bytes (sizeof)
struct // 3 elements, 0x4 bytes (sizeof)
{
/*0x03C*/ ULONG32 InitialPageProtection : 12; // 0 BitPosition
/*0x03C*/ ULONG32 SessionId : 19; // 12 BitPosition
/*0x03C*/ ULONG32 NoValidationNeeded : 1; // 31 BitPosition
};
}SECTION, * PSECTION;
```
先加载 loader 再加载 search,成功输出 shellcode 的地址,特征码匹配前八个字节,在自己的环境只输出了一个地址,如果输出多个地址可以考虑加长特征码。
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/20.png)
##### 方法2
通过获取到线程结构得到它的线程上下文,输出 RIP 的值应该也行,通过PCHUNTER看到shellcode运行的线程
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/21.png)
通过分析可知 shellcode 执行的线程具有如下特点:
与 TID=12 的线程入口相同
保持运行状态
据此可以筛选得到这个线程,通过线程结构体可以找到它的栈
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/22.png)
多次运行发现栈中存在 `GameSec.exe` 这个字符串。并且在它 - 0x28 的位置有一个地址,那个地址前八位和shellcode一致,所以同样可以爆破+特征码匹配。
```cpp
#include<ntifs.h>
#include <ntddk.h>
#include <ntstrsafe.h>
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)
#define MAX_BACKTRACE_DEPTH 20
ULONG64 num = 0;
NTSTATUS EnumerateKernelThreads();
typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
VOID DRIVERUNLOAD(_In_ struct _DRIVER_OBJECT* DriverObject)
{
kprintf(("unload\n"));
}
NTSTATUS EnumerateKernelThreads() {
PETHREAD T12 = NULL;
PETHREAD T;
PsLookupThreadByThreadId(12, &T12);
kprintf(("T12=%p\n"), T12);
ULONG64 Start = *(ULONG64 *)((ULONG64)T12 + 0x620);
HANDLE TargetThread = 0;
for (int i = 16; i < 0x20000; i+=4) {
T = NULL;
PsLookupThreadByThreadId(i, &T);
if (T) {
ULONG64 Startaddr = *(ULONG64 *)((ULONG64)T + 0x620);
if (Startaddr == Start) {
kprintf(("Found Thread=%p pThread=%p\n"), i,T);
TargetThread = i;
break;
}
}
}
if (T != NULL) {
ULONG64 StackBase = 0;
ULONG64 StackLimit = 0;
StackBase= *(ULONG64 *)((ULONG64)T + 0x38);
StackLimit=*(ULONG64 *)((ULONG64)T + 0x30);
kprintf(("Stackbase=%p StackLimit=%p\n"), StackBase, StackLimit);
for (ULONG64 addr = StackBase-0x10 ; addr > StackLimit; addr -= 8) {
if (!strcmp(addr, "GameSec.exe")) {
kprintf(("Found string in %p\n"), addr);
uintptr_t address;
for (ULONG64 i = 0x0; i <65536; i++)
{
address = (*(ULONG64*)(addr-0x28)) & 0xffffffff00000000;
address = address + 0x1000;
address = address + (i<<16);
if (MmIsAddressValid((PVOID)address) && *((ULONG64 *)address) == 0x7C8B483024748B48 )
{
kprintf(("shellcode found in %p\n"), address);
//DbgBreakPoint();
break;
}
}
break;
}
}
}
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
kprintf(("hello xia0ji233\n"));
EnumerateKernelThreads();
pDriver->DriverUnload = DRIVERUNLOAD;
return STATUS_SUCCESS;
}
```
先运行 Loader.sys,再运行EmurateThread.sys,可以成功输出shellcode的地址。
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/23.png)
##### 方法3
随后我发现线程结构体中的 TrapFrame 有点东西,通过一段时间的运行之后,发现它的一些寄存器中会带上点东西
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/24.png)
这里我选 Rdx,取前8位,暴力搜索4位(65536,可接受范围内)匹配。
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/25.png)
先运行 Loader.sys 再运行 Search3.sys,可以直接得到 shellcode 的地址。
##### 方法4
观察到 ETHTREAD 结构体中有个指针指向了距离shellcode比较近的位置
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/26.png)
获取这个指针的前八位,然后爆破,匹配特征码。
![](https://xia0ji233.pro/2024/04/22/tencent-race-2024-pre-final/27.png)
先运行Loader.sys,再运行 Search4.sys,即可获得shellcode的地址。
##### 方法5
挂起线程,此时会将线程上下文保存在栈顶中,再去遍历一遍栈,获得RIP指针,这里判断只需要拿 RSP 即可,当 -0x400==addr(+0x180是RSP相对于上下文结构体的偏移,0x400是context上下文大小)时,取出 RIP 即可。
先运行 Loader.sys,在运行search5.sys,即可输出shellcode。 大神之所以是大神,就是先要有NB的技术去分析问题,更要有耐心去分析和解决问题,这么多代码,单是C的都没耐心看完,还要分析一大堆汇编指令,还要写脚本,写测试程序等等,我连一行行仔细看的耐心都没有,这就是差距啊 我能看懂的不多,但当我看到这段代码的时候
```cpp
#include<stdio.h>
#include<string.h>
int main(){
char user[]="xia0ji233";
int n=strlen(user);
unsigned key=0;
for(int i=0;i<n;i++){
key=(key+user)*0x1003F;
}
printf("%u\n",key);
}
```
这是字符串哈希的自然溢出。多年没碰算法的我的DNA动了…… 沙发 大佬厉害 太高深,完全看不懂膜拜一下 太强了,学习学习,希望有朝一日可以赶上大佬的脚步 这些东西,不了解的人看起来真的是眼花缭乱!学习了,谢谢分享 我的乖乖,我纯往下拉都拉了半天 沙发 大佬厉害 感谢大佬分享 感谢大佬分享~ 不明觉厉,楼主前途无量 不明觉厉