dnf辅助外挂C++源代码(仅供学习参考)

更新时间:2024-05-29 07:51:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

独钓寒江雪

由于我的C用的比较少,所以大部分都用的汇编,部分地方用汇编写不是很方便,所以我用的C,由于只是学习,所以内核地址我没有计算都是硬编码的。过DNF主要分为三步,也许我的思路不太正确,反正可以OD调试,下断。 程序没怎么修边幅,因为只是测试,所以一般都没有写更改内核后的恢复,不过不妨碍使用。

第一步,这也是最起码的,你必须要能够打开游戏进程和线程,能够开打进程和线程后不被检测到

第二步,能够读写进村内存

第三步,能够用OD附加游戏进程 第四步,能够下硬件断点而不被检测

跳过NtReadVirtualMemory,NtWriteVirtualMemory函数头的钩子 代码:

#include

typedef struct _SERVICE_DESCRIPTOR_TABLE {

PVOID ServiceTableBase;

PULONG ServiceCounterTableBase; ULONG NumberOfService; ULONG ParamTableBase;

}SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE; //由于KeServiceDescriptorTable只有一项,这里就简单点了 extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;//KeServiceDescriptorTable为导出函数

///////////////////////////////////// VOID Hook(); VOID Unhook();

VOID OnUnload(IN PDRIVER_OBJECT DriverObject); //////////////////////////////////////

ULONG JmpAddress;//跳转到NtOpenProcess里的地址 ULONG JmpAddress1;//跳转到NtOpenProcess里的地址

ULONG OldServiceAddress;//原来NtOpenProcess的服务地址 ULONG OldServiceAddress1;//原来NtOpenProcess的服务地址 //////////////////////////////////////

__declspec(naked) NTSTATUS __stdcall MyNtReadVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress,

PVOID Buffer,

ULONG NumberOfBytesToRead, PULONG NumberOfBytesReaded) {

//跳过去 __asm {

push 0x1c

push 804eb560h //共十个字节 jmp [JmpAddress] } }

__declspec(naked) NTSTATUS __stdcall MyNtWriteVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer,

ULONG NumberOfBytesToWrite, PULONG NumberOfBytesReaded) {

//跳过去 __asm {

push 0x1c

push 804eb560h //共十个字节 jmp [JmpAddress1] } }

/////////////////////////////////////////////////// NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath) {

DriverObject->DriverUnload = OnUnload; DbgPrint(\ Hook();

return STATUS_SUCCESS; }

/////////////////////////////////////////////////////

VOID OnUnload(IN PDRIVER_OBJECT DriverObject) {

DbgPrint(\ Unhook(); }

///////////////////////////////////////////////////// VOID Hook()

{

ULONG Address, Address1;

Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0xBA * 4;//0x7A为NtOpenProcess服务ID

Address1 = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x115 * 4;//0x7A为NtOpenProcess服务ID

DbgPrint(\

OldServiceAddress = *(ULONG*)Address;//保存原来NtOpenProcess的地址 OldServiceAddress1 = *(ULONG*)Address1;//保存原来NtOpenProcess的地址 DbgPrint(\ DbgPrint(\

DbgPrint(\ DbgPrint(\

JmpAddress = (ULONG)0x805b528a + 7; //跳转到NtOpenProcess函数头+10的地方,这样在其前面写的JMP都失效了

JmpAddress1 = (ULONG)0x805b5394 + 7; DbgPrint(\ DbgPrint(\ __asm

{ //去掉内存保护 cli

mov eax,cr0 and eax,not 10000h mov cr0,eax }

*((ULONG*)Address) = (ULONG)MyNtReadVirtualMemory;//HOOK SSDT *((ULONG*)Address1) = (ULONG)MyNtWriteVirtualMemory;

__asm

{ //恢复内存保护 mov eax,cr0 or eax,10000h mov cr0,eax sti } }

////////////////////////////////////////////////////// VOID Unhook()

{

ULONG Address, Address1;

Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0xBA * 4;//查找SSDT Address1 = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x115 * 4;

__asm{ cli

mov eax,cr0 and eax,not 10000h mov cr0,eax }

*((ULONG*)Address) = (ULONG)OldServiceAddress;//还原SSDT *((ULONG*)Address1) = (ULONG)OldServiceAddress1;//还原SSDT

__asm{

mov eax,cr0 or eax,10000h mov cr0,eax sti }

DbgPrint(\}

由于它不断对DebugPort清零,所以要修改调试相关函数,使得所有的访问DebugPort的地方全部访问EPROCESS中的ExitTime字节,这样它怎么清零都无效了,也检测不到 代码: .386

.model flat, stdcall option casemap:none

include dnf_hook.inc

.const

Dspdo_1 equ 80643db6h Dmpp_1 equ 80642d5eh Dmpp_2 equ 80642d64h Dct_1 equ 806445d3h Dqm_1 equ 80643089h Kde_1 equ 804ff5fdh Dfe_1 equ 80644340h Pcp_1 equ 805d1a0dh

Mcp_1 equ 805b0c06h Mcp_2 equ 805b0d7fh Dmvos_1 equ 8064497fh Dumvos_1 equ 80644a45h Pet_1 equ 805d32f8h Det_1 equ 8064486ch Dep_1 equ 806448e6h

.code

;还原自己的Hook

DriverUnload proc pDriverObject:PDRIVER_OBJECT ret

DriverUnload endp

ModifyFuncAboutDbg proc addrOdFunc, cmd_1, cmd_2 pushad

mov ebx, addrOdFunc mov eax, cmd_1

mov DWORD ptr [ebx], eax mov eax, cmd_2

mov DWORD ptr [ebx + 4], eax popad ret

ModifyFuncAboutDbg endp

DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING cli

mov eax, cr0

and eax, not 10000h mov cr0, eax

invoke ModifyFuncAboutDbg, Dspdo_1, 90784789h, 0fde89090h invoke ModifyFuncAboutDbg, Dmpp_1, 90787e39h, 950f9090h invoke ModifyFuncAboutDbg, Dct_1, 90785e39h, 840f9090h invoke ModifyFuncAboutDbg, Dqm_1, 9078408bh, 45899090h invoke ModifyFuncAboutDbg, Kde_1, 90787839h, 13749090h invoke ModifyFuncAboutDbg, Dfe_1, 9078418bh, 0d2329090h invoke ModifyFuncAboutDbg, Pcp_1, 90784389h, 45f69090h invoke ModifyFuncAboutDbg, Mcp_1, 90785e39h, 950f9090h invoke ModifyFuncAboutDbg, Mcp_2, 90784a89h, 5e399090h invoke ModifyFuncAboutDbg, Dmvos_1, 9078498bh, 0cb3b9090h invoke ModifyFuncAboutDbg, Dumvos_1, 00787983h, 74909090h invoke ModifyFuncAboutDbg, Pet_1, 00787f83h, 74909090h invoke ModifyFuncAboutDbg, Det_1, 9078498bh, 0c9859090h

invoke ModifyFuncAboutDbg, Dep_1, 9078498bh, 0c9859090h ;invoke ModifyFuncAboutDbg, Dmpp_2, 8bc0950fh, 8b90c032h

mov eax, pDriverObject

assume eax : ptr DRIVER_OBJECT

mov [eax].DriverUnload, offset DriverUnload assume eax : nothing

mov eax, cr0

or eax, 10000h mov cr0, eax sti

mov eax, STATUS_SUCCESS ret

DriverEntry endp end DriverEntry

绕过NtOpenProcess,NtOpenThread,KiAttachProcess

以及最重要的,不能让它检测到有硬件断点,所以要对CONTEXT做一些伪装,把真实的DR0~DR7的数据存放到别的地方,OD访问的时候返回正确的数据,如果是DNF要获取上下文,就稍微做下手脚 代码: .386

.model flat, stdcall option casemap:none

include dnf_hook.inc

.const

NtOpenProcessHookAddr equ 805cc626h NtOpenProcessRetAddr equ 805cc631h NtOpenProcessNoChange equ 805cc62ch

NtOpenThreadHookAddr equ 805cc8a8h NtOpenThreadRetAddr equ 805cc8b3h NtOpenThreadNoChange equ 805cc8aeh

KiAttachProcessAddr equ 804f9a08h KiAttachProcessRetAddr equ 804f9a0fh

ObOpenObjectByPointerAddr equ 805bcc78h

NtGetContextThreadAddr equ 805d2551h;805c76a3h NtGetContextThreadRetAddr equ 805c76a7h;805d2555h .data

nameOffset dd ? threadCxtLink dd 0 tmpLink dd ?

.code

GetProcessName proc

invoke PsGetCurrentProcess mov ebx, eax

add ebx, nameOffset

invoke DbgPrint, $CTA0(\ push ebx

invoke DbgPrint, ebx pop ebx

invoke strncmp, $CTA0(\ push eax

invoke DbgPrint, $CTA0(\ pop eax ret

GetProcessName endp

HookCode proc

;执行被覆盖的代码

push dword ptr [ebp-38h] push dword ptr [ebp-24h] ;判断是否dnf的进程 invoke GetProcessName

.if !eax ;如果是DNF自己的进程,那么跳转回去执行它的Hook代码 pushad

invoke DbgPrint, $CTA0(\ popad

mov eax, NtOpenProcessNoChange;805c13e6h jmp eax

.else ;如果不是DNF自己的进程,那么直接调用ObOpenObjectByPointer,再返回到后面

pushad

invoke DbgPrint, $CTA0(\ popad

mov eax, ObOpenObjectByPointerAddr;805b13f0h call eax

mov ebx, NtOpenProcessRetAddr;805c13ebh

jmp ebx .endif

HookCode endp

;获取系统名称偏移 GetNameOffset proc epe local tmpOffset pushad

mov ebx, epe

invoke strlen, $CTA0(\ xor ecx, ecx @@:

push eax push ecx

invoke strncmp, $CTA0(\ pop ecx .if !eax pop eax

mov tmpOffset, ecx popad

mov eax, tmpOffset ret .elseif

pop eax inc ebx inc ecx

cmp ecx, 4096 je @F jmp @B .endif @@: popad

mov eax, -1 ret

GetNameOffset endp

Hook proc pushad

;头5字节跳转

mov eax, offset HookCode

sub eax, NtOpenProcessHookAddr;805c13e0h;805c13edh sub eax, 5

mov ebx, NtOpenProcessHookAddr;805c13e0h;805c13edh mov cl, 0E9h

mov BYTE PTR [ebx], cl

mov DWORD PTR [ebx + 1], eax popad ret

Hook endp

HookThreadCode proc ;执行被覆盖的代码

push dword ptr [ebp-34h] push dword ptr [ebp-20h] ;判断是否dnf的进程 invoke GetProcessName

.if !eax ;如果是DNF自己的进程,那么跳转回去执行它的Hook代码 pushad

invoke DbgPrint, $CTA0(\ popad

mov eax, NtOpenThreadNoChange;805c13e6h jmp eax

.else ;如果不是DNF自己的进程,那么直接调用ObOpenObjectByPointer,再返回到后面

pushad

invoke DbgPrint, $CTA0(\ popad

mov eax, ObOpenObjectByPointerAddr;805b13f0h call eax

mov ebx, NtOpenThreadRetAddr;805c13ebh jmp ebx .endif

HookThreadCode endp

HookThread proc pushad

;头5字节跳转

mov eax, offset HookThreadCode

sub eax, NtOpenThreadHookAddr;805c13e0h;805c13edh sub eax, 5

mov ebx, NtOpenThreadHookAddr;805c13e0h;805c13edh mov cl, 0E9h

mov BYTE PTR [ebx], cl

mov DWORD PTR [ebx + 1], eax popad ret

HookThread endp

HookDbg proc mov edi, edi push ebp mov ebp, esp push ebx push esi

mov esi, KiAttachProcessRetAddr jmp esi HookDbg endp

Dbg proc pushad

;头5字节跳转

mov eax, offset HookDbg

sub eax, KiAttachProcessAddr;805c13e0h;805c13edh sub eax, 5

mov ebx, KiAttachProcessAddr;805c13e0h;805c13edh mov cl, 0E9h

mov BYTE PTR [ebx], cl

mov DWORD PTR [ebx + 1], eax popad ret Dbg endp

;还原自己的Hook

DriverUnload proc pDriverObject:PDRIVER_OBJECT cli

mov eax, cr0

and eax, not 10000h mov cr0, eax

;还原进程处理

mov eax, 0ffc875ffh mov ebx, 805cc656h

mov DWORD ptr [ebx], eax mov eax, 43e8dc75h

mov DWORD ptr [ebx + 4], eax ;还原线程处理

mov eax, 0ffcc75ffh mov ebx, 805cc8d8h

mov DWORD ptr [ebx], eax mov eax, 0c1e8e075h

mov DWORD ptr [ebx + 4], eax

;还原调试处理

mov eax, 08b55ff8bh mov ebx, 804f9a08h

mov DWORD ptr [ebx], eax mov eax, 08b5653ech

mov DWORD ptr [ebx + 4], eax

mov eax, cr0

or eax, 10000h mov cr0, eax sti

ret

DriverUnload endp

;显示LinkTable的信息

ShowLinkTableInfo proc ptrLT pushad

invoke DbgPrint, $CTA0(\

mov ebx, ptrLT

mov eax, (LinkTable ptr [ebx]).ThreadHandle

invoke DbgPrint, $CTA0(\

mov ebx, ptrLT

mov eax, (LinkTable ptr [ebx]).Dr0Seg

invoke DbgPrint, $CTA0(\

mov ebx, ptrLT

mov eax, (LinkTable ptr [ebx]).Dr1Seg

invoke DbgPrint, $CTA0(\

mov ebx, ptrLT

mov eax, (LinkTable ptr [ebx]).Dr2Seg

invoke DbgPrint, $CTA0(\

mov ebx, ptrLT

mov eax, (LinkTable ptr [ebx]).Dr3Seg

invoke DbgPrint, $CTA0(\

mov ebx, ptrLT

mov eax, (LinkTable ptr [ebx]).Dr6Seg

invoke DbgPrint, $CTA0(\

mov ebx, ptrLT

mov eax, (LinkTable ptr [ebx]).Dr7Seg

invoke DbgPrint, $CTA0(\

mov ebx, ptrLT

mov eax, (LinkTable ptr [ebx]).LinkPtr

invoke DbgPrint, $CTA0(\

mov ebx, ptrLT

mov eax, (LinkTable ptr [ebx]).NextLinkPtr

invoke DbgPrint, $CTA0(\ popad ret

ShowLinkTableInfo endp

;判断该线程是否存在

;如果不存在则返回0,存在则返回指向该链表的指针,1代表链表为空 ExsitsLinkTable proc pHandle pushad

mov eax, threadCxtLink .if !eax ;链表为空 pushad

invoke DbgPrint, $CTA0(\ popad

popad

mov eax, 1 ret .endif @@:

mov ebx, (LinkTable ptr [eax]).ThreadHandle cmp ebx, pHandle ;如果匹配已经存在 je @F

mov eax, (LinkTable ptr [eax]).NextLinkPtr .if !eax ;已经到达末尾,没有找到匹配 pushad

invoke DbgPrint, $CTA0(\ popad

popad

xor eax, eax ret .endif jmp @B

@@: pushad

invoke DbgPrint, $CTA0(\ popad

invoke ShowLinkTableInfo, eax ;返回链表指针 mov tmpLink, eax popad

mov eax, tmpLink ret

ExsitsLinkTable endp

;拷贝Context到LinkTable中

CopyContextToLinkTable proc ptrContext, ptrLT pushad

mov ebx, ptrContext mov edx, ptrLT mov ecx, 4 @@:

mov eax, DWORD ptr [ebx + ecx] mov DWORD ptr [edx + ecx], eax add ecx, 4 cmp ecx, 18h jbe @B popad ret

CopyContextToLinkTable endp

;添加LinkTable表

AddLinkTable proc pHandle, ptrContext pushad

invoke ExsitsLinkTable, pHandle .if eax > 1

;已经存在只需要更新dr寄存器即可

invoke CopyContextToLinkTable, eax, ptrContext .else

push eax

invoke ExAllocatePool, 1, size LinkTable .if eax

;申请内存成功 mov ebx, eax pop eax

;置地一个元素 mov ecx, pHandle

mov (LinkTable ptr [ebx]).ThreadHandle, ecx ;拷贝dr寄存器的值

invoke CopyContextToLinkTable, ptrContext, ebx ;置另外两个元素

mov (LinkTable ptr [ebx]).LinkPtr, ebx mov (LinkTable ptr [ebx]).NextLinkPtr, 0 invoke ShowLinkTableInfo, ebx

;把新的链表项添加到链表中 .if eax == 1

;如果链表为空,直接加在表头 mov threadCxtLink, ebx .else

;如果链表不为空则加到末尾 mov eax, threadCxtLink @@:

;指向下一个元素

mov ecx, (LinkTable ptr [eax]).NextLinkPtr test ecx, ecx je @F

mov eax, ecx jmp @B @@:

mov (LinkTable ptr [eax]).NextLinkPtr, ebx .endif .else

;申请内存失败 pop eax pushad

invoke DbgPrint, $CTA0(\ popad jmp @F .endif .endif @@: popad ret

AddLinkTable endp

;判断进程是否过虑进程

;如果是需要过虑的进程返回值为1,否则返回0 IsFilterProcess proc pushad

;获取当前进程名

invoke PsGetCurrentProcess mov ebx, eax

add ebx, nameOffset

invoke DbgPrint, $CTA0(\ invoke strncmp, $CTA0(\ test eax, eax jne @F popad

mov eax, 1 ret @@: popad

xor eax, eax ret

IsFilterProcess endp

;显示Context的调试寄存器 ShowDrRegInfo proc ptrContext pushad

invoke DbgPrint, $CTA0(\

mov ebx, ptrContext

mov eax, DWORD ptr [ebx + 4]

invoke DbgPrint, $CTA0(\

mov ebx, ptrContext

mov eax, DWORD ptr [ebx + 8]

invoke DbgPrint, $CTA0(\

mov ebx, ptrContext

mov eax, DWORD ptr [ebx + 0ch]

invoke DbgPrint, $CTA0(\

mov ebx, ptrContext

mov eax, DWORD ptr [ebx + 10h]

invoke DbgPrint, $CTA0(\

mov ebx, ptrContext

mov eax, DWORD ptr [ebx + 14h]

invoke DbgPrint, $CTA0(\

mov ebx, ptrContext

mov eax, DWORD ptr [ebx + 18h]

invoke DbgPrint, $CTA0(\

popad ret

ShowDrRegInfo endp

;恢复被隐藏的dr寄存器

RecoveryDrReg proc ptrContext, pHandle pushad

;定位到LinkTable

mov ebx, threadCxtLink NEXT:

test ebx, ebx

jne @F ;如果没有遍历完 popad ret @@:

mov eax, (LinkTable ptr [ebx]).ThreadHandle cmp eax, pHandle

je @F ;如果找到匹配项

mov ebx, (LinkTable ptr [ebx]).NextLinkPtr jmp NEXT @@:

;拷贝完毕后立即结束

invoke CopyContextToLinkTable, ebx, ptrContext xor ebx, ebx jmp NEXT

RecoveryDrReg endp

;清空Context的dr寄存器 ClearDrReg proc ptrContext pushad

mov ebx, ptrContext mov ecx, 4 @@:

mov DWORD ptr [ebx + ecx], 0 add ecx, 4 cmp ecx, 18h jbe @B pushad

invoke DbgPrint, $CTA0(\ popad

invoke ShowDrRegInfo, ptrContext popad ret

ClearDrReg endp

;NtGetContextThread钩子代码 NtGetContextThreadHookCode proc ;ebx存放CONTEXT指针

mov ebx, DWORD ptr [ebp + 10h] ;线程句柄

mov edx, DWORD ptr [ebp + 0ch] pushad

invoke ShowDrRegInfo, ebx invoke IsFilterProcess .if eax ;如果是DNF.exe

invoke AddLinkTable, edx, ebx invoke ClearDrReg, ebx .else ;如果不是DNF.exe

invoke RecoveryDrReg, ebx, edx .endif

invoke ShowDrRegInfo, ebx ;执行被覆盖的代码 popad

mov eax, esi pop esi leave ret

NtGetContextThreadHookCode endp

;NtGetContextThread加跳转 HookNtGetContextThread proc pushad

;头5字节跳转

mov eax, offset NtGetContextThreadHookCode

sub eax, NtGetContextThreadAddr;805c13e0h;805c13edh sub eax, 5

mov ebx, NtGetContextThreadAddr;805c13e0h;805c13edh mov cl, 0E9h

mov BYTE PTR [ebx], cl

mov DWORD PTR [ebx + 1], eax popad ret

HookNtGetContextThread endp

DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING invoke DbgPrint, $CTA0(\ invoke PsGetCurrentProcess invoke GetNameOffset, eax

mov nameOffset, eax cmp eax, -1 je @F

mov nameOffset, eax cli

mov eax, cr0

and eax, not 10000h mov cr0, eax

call Hook

call HookThread call Dbg

call HookNtGetContextThread

mov eax, pDriverObject

assume eax : ptr DRIVER_OBJECT

mov [eax].DriverUnload, offset DriverUnload assume eax : nothing

mov eax, cr0

or eax, 10000h mov cr0, eax sti

invoke DbgPrint, $CTA0(\@@:

mov eax, STATUS_SUCCESS ret

DriverEntry endp end DriverEntry

本文来源:https://www.bwwdw.com/article/lau7.html

Top