c3p0报了很多空指针

作者在学习c3p0做单表curd项目时,运行测试报了很多异常,一直处于连接池读取c3p0 - cofig.xml文件的死循环。总结了三种解决方法:开启sql相关服务;给服务器授权;确保xml文件路径正确。

## c3p0运行时报了很多java.Long.NullPointerException

在最近学习c3p0的时候,自己利用链接池的便捷去做了一个单表curd的项目,但是在运行测试的时候,报了很多异常。

在这里插入图片描述
当看到空指针的时候我还以为我的方法return null了,所以打了断点去观察了一下。结果发现一直处于连接池去读取c3p0-cofig.xml文件的死循环中,于是我就开始了问老师+问度娘的漫长过程中,好在最后解决了,我总结了一下我问老师+问度娘的解决方法:

  1. 有可能是sql的相关服务没有开启

    因为下面报了一句 java.lang.RuntimeException: java.sq1.SQLException:Connections could not be acquired from the underlying database!意思是:“无法从底层数据库获取连接!“

    解决方法很简单:
    选中此电脑然后右键找到管理点击,在里面找到服务和应用程序然后找到你用的数据库的相关服务关闭在重新打开就行了。
    在这里插入图片描述

  2. 第二种方法是有可能你的DataSource读取了c3p0-cofig.xml,但是你的服务器没有给授权,这时候只需要连接你的数据库输入grant all privileges on . to ‘root’@’%’ identified by ‘root’ with grant option;
    flush privileges;

    并且按两下回车就可以了。
    在这里插入图片描述

  3. 第三种方法也是最扯淡的方法,那就是你的xml文件路径有问题,导致你的DataSource读取不到c3p0配置文件,这时候只需要把原来的删除了然后在拉到src下面就可以了,加入你原来的也在src下面,那你也同样在重新拉一次。

在这里插入图片描述

总结:说实话看到这种异常还是蛮头疼的,毕竟不好找到问题的根源性,希望这篇文章对你有所帮助。

根据汇编转C代码 00000001408875A4 ; __int64 __fastcall DbgkpPostFakeThreadMessages(PEPROCESS targerPorcess, PDEBUG_OBJECT debug_object, PETHREAD Thread, PETHREAD *OutThread, PETHREAD *OutThread2) 00000001408875A4 DbgkpPostFakeThreadMessages proc near ; CODE XREF: DbgkpPostFakeProcessCreateMessages+54↑p 00000001408875A4 ; DbgkpSetProcessDebugObject+E4↓p 00000001408875A4 ; DATA XREF: ... 00000001408875A4 var_1F8 = qword ptr -1F8h 00000001408875A4 var_1E8 = byte ptr -1E8h 00000001408875A4 var_1E7 = byte ptr -1E7h 00000001408875A4 var_1E4 = dword ptr -1E4h 00000001408875A4 PROCESS = qword ptr -1E0h 00000001408875A4 var_1D8 = qword ptr -1D8h 00000001408875A4 var_1D0 = qword ptr -1D0h 00000001408875A4 var_1C8 = qword ptr -1C8h 00000001408875A4 var_1C0 = qword ptr -1C0h 00000001408875A4 var_1B8 = qword ptr -1B8h 00000001408875A4 var_1B0 = qword ptr -1B0h 00000001408875A4 var_1A8 = qword ptr -1A8h 00000001408875A4 var_1A0 = qword ptr -1A0h 00000001408875A4 var_198 = qword ptr -198h 00000001408875A4 var_190 = qword ptr -190h 00000001408875A4 var_message = _DBGKM_APIMSG ptr -188h 00000001408875A4 ApcState = _KAPC_STATE ptr -78h 00000001408875A4 var_48 = qword ptr -48h 00000001408875A4 OutThread2 = qword ptr 28h 00000001408875A4 ; __unwind { // __GSHandlerCheck_SEH 00000001408875A4 mov r11, rsp ; 保存原始栈指针 00000001408875A7 push rbx ; 保存非易失寄存器 00000001408875A8 push rsi 00000001408875A9 push rdi 00000001408875AA push r12 00000001408875AC push r13 00000001408875AE push r14 00000001408875B0 push r15 00000001408875B2 sub rsp, 1E0h ; 分配栈空间 (480字节) 00000001408875B9 mov rax, cs:__security_cookie ; 安全Cookie检查初始化 00000001408875C0 xor rax, rsp ; 计算安全Cookie 00000001408875C3 NtWaitForDebugEvent$filt$0_0: ; 存储安全Cookie 00000001408875C3 mov [rsp+218h+var_48], rax 00000001408875CB mov [rsp+218h+var_1C0], r9 ; 保存第4个参数 (OutThread) 00000001408875D0 mov rbx, r8 ; 保存第3个参数 00000001408875D3 mov [rsp+218h+var_1D0], rdx ; 保存第2个参数 (DebugObject) 00000001408875D8 mov r14, rcx ; 保存第1个参数 (TargetProcess) 00000001408875DB mov [rsp+218h+PROCESS], rcx ; 再次保存TargetProcess 00000001408875E0 mov [rsp+218h+var_1A0], rcx 00000001408875E5 mov [rsp+218h+var_198], rdx 00000001408875ED mov rsi, r8 ; rsi = 第3个参数 00000001408875F0 mov [rsp+218h+var_190], r9 00000001408875F8 mov rax, [rsp+218h+OutThread2] ; 获取第5个参数 (栈传递) 0000000140887600 DbgkQueueUserExceptionReport_0: ; 保存第5个参数 0000000140887600 mov [rsp+218h+var_1B8], rax 0000000140887605 xorps xmm0, xmm0 ; 初始化APC状态结构 0000000140887605 ; 清零XMM0寄存器 0000000140887608 movups xmmword ptr [r11-78h], xmm0 ; 清零ApcState结构 000000014088760D movups xmmword ptr [r11-68h], xmm0 ; Move Unaligned Four Packed Single-FP 0000000140887612 movups xmmword ptr [r11-58h], xmm0 ; Move Unaligned Four Packed Single-FP 0000000140887617 xor edx, edx ; 初始化局部变量内存 0000000140887617 ; 清零作为memset参数 0000000140887619 mov r8d, 110h ; 设置大小 (272字节) 000000014088761F lea rcx, [r11-188h] ; 目标地址 0000000140887626 call memset ; 调用内存清零函数 000000014088762B xor r15d, r15d ; 初始化变量 000000014088762B ; r15d = 0 000000014088762E mov [rsp+218h+var_1D8], r15 ; 清零局部变量 0000000140887633 xor edi, edi ; edi = 0 0000000140887635 mov rax, gs:KPCR.kprcb.CurrentThread ; 获取当前线程 0000000140887635 ; 获取当前ETHREAD 000000014088763E mov [rsp+218h+var_1B0], rax ; 保存当前线程指针 0000000140887643 mov r12d, 0C0000001h ; 预设错误码 STATUS_UNSUCCESSFUL 0000000140887649 test rbx, rbx ; 检查第3个参数是否为NULL 000000014088764C jz short loc_140887669 ; 如果为NULL则跳转 000000014088764E mov r15, rbx ; 处理非NULL的线程参数 000000014088764E ; r15 = 输入线程 0000000140887651 mov [rsp+218h+var_1D8], rbx ; 保存到局部变量 0000000140887656 mov r14d, 'OgbD' ; 设置对象标签 'DBg' 000000014088765C mov edx, r14d ; Tag 标签作为参数 000000014088765F mov rcx, rbx ; Object 对象指针 0000000140887662 call ObfReferenceObjectWithTag ; 增加对象引用计数 0000000140887667 jmp short loc_14088767C ; 跳转到公共代码 0000000140887669 ; --------------------------------------------------------------------------- 0000000140887669 loc_140887669: ; CODE XREF: DbgkpPostFakeThreadMessages+A8↑j 0000000140887669 xor edx, edx ; 处理线程参数为NULL的情况 (遍历进程线程) 0000000140887669 ; 从第一个线程开始遍历 000000014088766B mov rcx, r14 ; TargetProcess 000000014088766E call PsGetNextProcessThread ; 获取进程第一个线程 0000000140887673 mov rbx, rax ; rbx = 当前线程 0000000140887676 mov r14d, 4F676244h ; 设置对象标签 'DBg' 000000014088767C loc_14088767C: ; CODE XREF: DbgkpPostFakeThreadMessages+C3↑j 000000014088767C mov [rsp+218h+var_1C8], rbx ; 公共代码路径 000000014088767C ; 保存当前线程 0000000140887681 test rsi, rsi ; 检查第3个参数 0000000140887684 setz r13b ; 如果为NULL则r13b=1 0000000140887688 mov [rsp+218h+var_1E8], r13b ; 保存标志 000000014088768D loc_14088768D: ; CODE XREF: DbgkpPostFakeThreadMessages+3AC↓j 000000014088768D test rbx, rbx ; 线程遍历主循环 000000014088768D ; 检查当前线程是否有效 0000000140887690 jz loc_1408878D1 ; 如果无效跳转到结束 0000000140887696 test rdi, rdi ; 释放前一线程对象 0000000140887696 ; 检查前一线程指针 0000000140887699 jz short loc_1408876A6 ; 如果为空则跳过 000000014088769B mov edx, r14d ; Tag 标签参数 000000014088769E mov rcx, rdi ; Object 线程对象 00000001408876A1 call ObfDereferenceObjectWithTag ; 减少引用计数 00000001408876A6 loc_1408876A6: ; CODE XREF: DbgkpPostFakeThreadMessages+F5↑j 00000001408876A6 mov rdi, rbx ; 处理当前线程 00000001408876A6 ; 保存当前线程到rdi 00000001408876A9 mov [rsp+218h+var_1A8], rbx ; 保存到局部变量 00000001408876AE mov edx, r14d ; Tag 标签参数 00000001408876B1 mov rcx, rbx ; Object 当前线程 00000001408876B4 call ObfReferenceObjectWithTag ; 增加引用计数 00000001408876B9 test dword ptr [rbx+74h], 400h ; 检查线程状态标志 00000001408876B9 ; 检查ThreadFlags+0x74 00000001408876B9 ; ULONG SystemThread:1; //0x74 00000001408876C0 jnz loc_14088793B ; 如果置位则跳过此线程 表示它是系统线程 00000001408876C6 mov eax, [rbx+_ETHREAD.___u21.CrossThreadFlags] ; 读取Thread->CrossThreadFlags 00000001408876CC test al, 2 ; 表示线程是否已经被插入到进程的线程列表中。当线程被创建并成功插入,此标志被设置 00000001408876CE jnz short loc_1408876EB ; 如果已设置则继续 00000001408876D0 mov rdx, [rsp+218h+var_1B0] ; 同步线程插入操作 00000001408876D0 ; 当前线程 00000001408876D5 mov rcx, rbx ; 目标线程 00000001408876D8 call PsSynchronizeWithThreadInsertion ; 等待线程可用 00000001408876DD mov eax, [rbx+510h] ; 再次读取CrossThreadFlags 00000001408876E3 test al, 2 ; 表示线程是否已经被插入到进程的线程列表中。当线程被创建并成功插入,此标志被设置 00000001408876E5 jz loc_14088793B ; 如果未设置则跳过线程 00000001408876EB loc_1408876EB: ; CODE XREF: DbgkpPostFakeThreadMessages+12A↑j 00000001408876EB lea rcx, [rbx+_ETHREAD.RundownProtect] ; 获取线程运行保护 00000001408876EB ; Thread->RundownProtect 00000001408876F2 call ExAcquireRundownProtection ; 获取运行保护 00000001408876F7 test al, al ; 检查是否成功 00000001408876F9 jz short loc_140887719 ; 失败则跳转 00000001408876FB mov esi, 0Ah ; 挂起线程 00000001408876FB ; 设置状态标志为0xA (挂起成功) 0000000140887700 mov [rsp+218h+var_1E4], esi ; 保存状态标志 0000000140887704 xor edx, edx ; PreviousMode = Kernel 0000000140887706 mov rcx, rbx ; 线程对象 0000000140887709 call PsSuspendThread ; 挂起线程 000000014088770E test eax, eax ; 检查返回值 0000000140887710 js short loc_140887722 ; 失败则跳转 0000000140887712 mov esi, 2Ah ; '*' ; 设置状态标志为0x2A 0000000140887717 jmp short loc_14088771E ; 跳转 0000000140887719 ; --------------------------------------------------------------------------- 0000000140887719 loc_140887719: ; CODE XREF: DbgkpPostFakeThreadMessages+155↑j 0000000140887719 mov esi, 12h ; 运行保护获取失败处理 0000000140887719 ; 设置状态标志为0x12 000000014088771E loc_14088771E: ; CODE XREF: DbgkpPostFakeThreadMessages+173↑j 000000014088771E mov [rsp+218h+var_1E4], esi ; 保存状态标志 0000000140887722 loc_140887722: ; CODE XREF: DbgkpPostFakeThreadMessages+16C↑j 0000000140887722 xor edx, edx ; 初始化消息结构 0000000140887722 ; 清零memset参数 0000000140887724 mov r8d, 110h ; 大小 000000014088772A lea rcx, [rsp+218h+var_message] ; 目标地址 0000000140887732 call memset ; 初始化消息缓冲区 0000000140887737 test r13b, r13b ; 检查是否需要处理系统DLL 0000000140887737 ; 检查标志 000000014088773A jz loc_140887843 ; 如果为0则跳过 0000000140887740 test sil, 10h ; 检查状态标志位4 0000000140887744 jnz loc_140887843 ; 如果置位则跳过 000000014088774A mov r13b, 1 ; 处理系统DLL消息 000000014088774A ; 设置标志 000000014088774D mov [rsp+218h+var_1E7], r13b 0000000140887752 mov dword ptr [rsp+218h+var_message.ApiNumber], 2 ; 设置处理模式 000000014088775D mov r12, [rsp+218h+PROCESS] ; 获取进程的Section句柄 000000014088775D ; TargetProcess 0000000140887762 mov rcx, [r12+_EPROCESS.SectionObject] ; Process->SectionHandle 000000014088776A test rcx, rcx ; 检查是否为NULL 000000014088776D jz short loc_14088777E ; 是则跳转 000000014088776F call DbgkpSectionToFileHandle ; 转换Section对象为句柄 0000000140887774 mov qword ptr [rsp+218h+var_message.u+8], rax ; 保存句柄 000000014088777C jmp short loc_140887787 ; 跳转 000000014088777E ; --------------------------------------------------------------------------- 000000014088777E loc_14088777E: ; CODE XREF: DbgkpPostFakeThreadMessages+1C9↑j 000000014088777E and qword ptr [rsp+218h+var_message.u+8], 0 ; 清空句柄变量 0000000140887787 loc_140887787: ; CODE XREF: DbgkpPostFakeThreadMessages+1D8↑j 0000000140887787 mov rax, [r12+_EPROCESS.SectionBaseAddress] ; 附加到目标进程 0000000140887787 ; Process->Win32Process 000000014088778F mov qword ptr [rsp+218h+var_message.u+10h], rax 0000000140887797 lea rdx, [rsp+218h+ApcState] ; ApcState APC状态指针 000000014088779F mov rcx, r12 ; PROCESS 目标进程 00000001408877A2 call KeStackAttachProcess ; 附加到进程空间 00000001408877A7 nop ; No Operation 00000001408877A8 loc_1408877A8: ; DATA XREF: .rdata:00000001400B5454↑o 00000001408877A8 ; __try { // __except at loc_1408877D9 ; 在目标进程空间中获取NT头 00000001408877A8 mov rcx, [r12+520h] ; Win32Process 00000001408877B0 call RtlImageNtHeader ; 获取PE头 00000001408877B5 test rax, rax ; 检查是否成功 00000001408877B8 jz short loc_1408877D7 ; 失败则跳转 00000001408877BA and qword ptr [rsp+218h+var_message.u+28h], 0 ; 保存PE头信息 00000001408877BA ; 清空变量 00000001408877C3 mov ecx, [rax+0Ch] ; SizeOfHeaders 00000001408877C6 mov dword ptr [rsp+218h+var_message.u+18h], ecx ; 保存 00000001408877CD mov eax, [rax+10h] ; SizeOfImage 00000001408877D0 mov dword ptr [rsp+218h+var_message.u+1Ch], eax ; 保存 00000001408877D7 loc_1408877D7: ; CODE XREF: DbgkpPostFakeThreadMessages+214↑j 00000001408877D7 jmp short DbgkRegisterErrorPort_0 ; 跳转到清理 00000001408877D7 ; } // starts at 1408877A8 00000001408877D9 ; --------------------------------------------------------------------------- 00000001408877D9 loc_1408877D9: ; DATA XREF: .rdata:00000001400B5454↑o 00000001408877D9 ; __except(1) // owned by 1408877A8 ; __except异常处理 00000001408877D9 and qword ptr [rsp+218h+var_message.u+28h], 0 ; 异常清空变量 00000001408877E2 and dword ptr [rsp+218h+var_message.u+18h], 0 ; Logical AND 00000001408877EA and dword ptr [rsp+218h+var_message.u+1Ch], 0 ; Logical AND 00000001408877F2 mov r14d, 'OgbD' ; 恢复标签 00000001408877F8 mov r15, [rsp+218h+var_1D8] ; 恢复线程指针 00000001408877FD mov esi, [rsp+218h+var_1E4] ; 恢复状态标志 0000000140887801 mov r13b, [rsp+218h+var_1E7] ; 恢复标志 0000000140887806 mov rdi, [rsp+218h+var_1A8] ; 恢复当前线程 000000014088780B mov rbx, [rsp+218h+var_1C8] 0000000140887810 mov rax, [rsp+218h+var_1A0] 0000000140887815 mov [rsp+218h+PROCESS], rax ; 恢复进程指针 000000014088781A mov rax, [rsp+218h+var_198] 0000000140887822 mov [rsp+218h+var_1D0], rax ; 恢复DebugObject 0000000140887827 mov rax, [rsp+218h+var_190] 000000014088782F mov [rsp+218h+var_1C0], rax ; 恢复OutThread 0000000140887834 DbgkRegisterErrorPort_0: ; CODE XREF: DbgkpPostFakeThreadMessages:loc_1408877D7↑j 0000000140887834 lea rcx, [rsp+218h+ApcState] ; ApcState 分离目标进程 0000000140887834 ; APC状态指针 000000014088783C call KeUnstackDetachProcess ; 分离进程 0000000140887841 jmp short loc_140887860 ; 跳转到消息发送 0000000140887843 ; --------------------------------------------------------------------------- 0000000140887843 loc_140887843: ; CODE XREF: DbgkpPostFakeThreadMessages+196↑j 0000000140887843 ; DbgkpPostFakeThreadMessages+1A0↑j 0000000140887843 xor r13b, r13b ; 非系统DLL处理路径 0000000140887843 ; 清除标志 0000000140887846 mov dword ptr [rsp+218h+var_message.ApiNumber], 1 ; 设置处理模式 0000000140887851 mov rax, [rbx+_ETHREAD.Win32StartAddress] 0000000140887858 mov qword ptr [rsp+218h+var_message.u+8], rax ; 保存进程ID 0000000140887860 loc_140887860: ; CODE XREF: DbgkpPostFakeThreadMessages+29D↑j 0000000140887860 mov rax, [rsp+218h+var_1D0] ; 发送调试消息 0000000140887860 ; DebugObject 0000000140887865 mov [rsp+218h+var_1F8], rax ; 参数5: PRKEVENT 000000014088786A mov r9d, esi ; 参数4: 消息类型 000000014088786D lea r8, [rsp+218h+var_message] ; 参数3: 消息缓冲区 0000000140887875 mov rdx, rbx ; 参数2: 线程指针 0000000140887878 mov rcx, [rsp+218h+PROCESS] ; 参数1: 进程指针 000000014088787D call DbgkpQueueMessage ; 发送消息到调试端口 0000000140887882 mov r12d, eax ; 保存返回状态 0000000140887885 test eax, eax ; 检查消息发送结果 0000000140887885 ; 检查状态 0000000140887887 jns short loc_1408878FF ; 成功则跳转 0000000140887889 test sil, 20h ; 错误处理:恢复线程状态 0000000140887889 ; 检查是否挂起了线程 000000014088788D jz short loc_140887899 ; 未挂起则跳过 000000014088788F xor edx, edx ; PreviousMode = Kernel 0000000140887891 mov rcx, rbx ; 线程对象 0000000140887894 call PsResumeThread ; 恢复线程 0000000140887899 loc_140887899: ; CODE XREF: DbgkpPostFakeThreadMessages+2E9↑j 0000000140887899 test sil, 8 ; 检查是否获取了运行保护 000000014088789D jz short loc_1408878AB ; 未获取则跳过 000000014088789F lea rcx, [rbx+4F8h] ; Thread->RundownProtect 00000001408878A6 call ExReleaseRundownProtection_1 ; 释放运行保护 00000001408878AB loc_1408878AB: ; CODE XREF: DbgkpPostFakeThreadMessages+2F9↑j 00000001408878AB cmp dword ptr [rsp+218h+var_message.ApiNumber], 2 ; 清理句柄资源 00000001408878AB ; 检查是否系统DLL模式 00000001408878B3 jnz short loc_1408878C9 ; 不是则跳过 00000001408878B5 mov rcx, qword ptr [rsp+218h+var_message.u+8] ; 获取句柄 00000001408878BD test rcx, rcx ; 检查是否有效 00000001408878C0 jz short loc_1408878C9 ; 无效则跳过 00000001408878C2 xor edx, edx ; PreviousMode = Kernel 00000001408878C4 call ObCloseHandle ; 关闭句柄 00000001408878C9 loc_1408878C9: ; CODE XREF: DbgkpPostFakeThreadMessages+30F↑j 00000001408878C9 ; DbgkpPostFakeThreadMessages+31C↑j 00000001408878C9 mov rcx, rbx ; 获取下一个线程 00000001408878C9 ; 当前线程 00000001408878CC call PsQuitNextProcessThread ; 移动到下一个线程 00000001408878D1 loc_1408878D1: ; CODE XREF: DbgkpPostFakeThreadMessages+EC↑j 00000001408878D1 test r12d, r12d ; 线程遍历结束处理 00000001408878D1 ; 检查最终状态 00000001408878D4 jns short loc_140887955 ; 成功则跳转 00000001408878D6 test r15, r15 ; 错误处理:释放对象引用 00000001408878D6 ; 检查输入线程 00000001408878D9 jz short loc_1408878E6 ; 为空则跳过 00000001408878DB mov edx, r14d ; Tag 00000001408878DE mov rcx, r15 ; Object 00000001408878E1 call ObfDereferenceObjectWithTag ; 释放引用 00000001408878E6 loc_1408878E6: ; CODE XREF: DbgkpPostFakeThreadMessages+335↑j 00000001408878E6 test rdi, rdi ; 检查当前线程 00000001408878E9 jz loc_140887982 ; 为空则跳转到结束 00000001408878EF mov edx, r14d ; Tag 00000001408878F2 mov rcx, rdi ; Object 00000001408878F5 call ObfDereferenceObjectWithTag ; 释放引用 00000001408878FA jmp loc_140887982 ; 跳转到结束 00000001408878FF ; --------------------------------------------------------------------------- 00000001408878FF loc_1408878FF: ; CODE XREF: DbgkpPostFakeThreadMessages+2E3↑j 00000001408878FF test r13b, r13b ; 消息发送成功处理 00000001408878FF ; 检查系统DLL标志 0000000140887902 jz short loc_140887936 ; 未设置则跳过 0000000140887904 xor r13b, r13b ; 发送系统DLL消息 0000000140887907 mov [rsp+218h+var_1E8], r13b ; 清除标志 000000014088790C mov edx, r14d ; Tag 000000014088790F mov rcx, rbx ; 线程对象 0000000140887912 call ObfReferenceObjectWithTag ; 增加引用计数 0000000140887917 mov r15, rbx ; 保存当前线程 000000014088791A mov [rsp+218h+var_1D8], rbx ; 保存当前线程 000000014088791F lea r8, [rsp+218h+var_message] ; 消息缓冲区 0000000140887927 mov rdx, [rsp+218h+var_1D0] ; DebugObject 000000014088792C mov rcx, rbx ; PVOID 000000014088792F call DbgkSendSystemDllMessages_0 ; 发送系统DLL消息 0000000140887934 jmp short loc_14088793B ; 获取下一个线程 0000000140887934 ; 当前线程 0000000140887936 ; --------------------------------------------------------------------------- 0000000140887936 loc_140887936: ; CODE XREF: DbgkpPostFakeThreadMessages+35E↑j 0000000140887936 mov r13b, [rsp+218h+var_1E8] 000000014088793B loc_14088793B: ; CODE XREF: DbgkpPostFakeThreadMessages+11C↑j 000000014088793B ; DbgkpPostFakeThreadMessages+141↑j ... 000000014088793B mov rdx, rbx ; 获取下一个线程 000000014088793B ; 当前线程 000000014088793E mov rcx, [rsp+218h+PROCESS] ; 目标进程 0000000140887943 call PsGetNextProcessThread ; 获取下一个线程 0000000140887948 mov rbx, rax ; 更新当前线程 000000014088794B mov [rsp+218h+var_1C8], rax ; 保存 0000000140887950 jmp loc_14088768D ; 线程遍历主循环 0000000140887950 ; 检查当前线程是否有效 0000000140887955 ; --------------------------------------------------------------------------- 0000000140887955 loc_140887955: ; CODE XREF: DbgkpPostFakeThreadMessages+330↑j 0000000140887955 test r15, r15 ; 成功退出路径 0000000140887955 ; 检查输入线程 0000000140887958 jz short loc_14088796C ; 为空则跳过 000000014088795A mov rax, [rsp+218h+var_1C0] ; 设置输出参数 000000014088795A ; OutThread指针 000000014088795F mov [rax], r15 ; 保存线程指针 0000000140887962 mov rax, [rsp+218h+var_1B8] ; 第5个参数指针 0000000140887967 mov [rax], rdi ; 保存当前线程 000000014088796A jmp short loc_140887982 ; 跳转到结束 000000014088796C ; --------------------------------------------------------------------------- 000000014088796C loc_14088796C: ; CODE XREF: DbgkpPostFakeThreadMessages+3B4↑j 000000014088796C test rdi, rdi ; 无输入线程的清理 000000014088796F jz short loc_14088797C ; 检查当前线程 000000014088796F ; 为空则跳过 0000000140887971 mov edx, r14d ; Tag 0000000140887974 mov rcx, rdi ; 线程对象 0000000140887977 call ObfDereferenceObjectWithTag ; 释放引用 000000014088797C loc_14088797C: ; CODE XREF: DbgkpPostFakeThreadMessages+3CB↑j 000000014088797C mov r12d, 0C0000001h ; 设置错误码 STATUS_UNSUCCESSFUL 0000000140887982 loc_140887982: ; CODE XREF: DbgkpPostFakeThreadMessages+345↑j 0000000140887982 ; DbgkpPostFakeThreadMessages+356↑j ... 0000000140887982 mov eax, r12d ; 函数退出 0000000140887982 ; 返回值 = 状态码 0000000140887985 mov rcx, [rsp+218h+var_48] ; 恢复安全Cookie 000000014088798D xor rcx, rsp ; StackCookie 0000000140887990 call __security_check_cookie ; 安全检查 0000000140887995 add rsp, 1E0h ; Add 000000014088799C pop r15 000000014088799E pop r14 00000001408879A0 pop r13 00000001408879A2 pop r12 00000001408879A4 pop rdi 00000001408879A5 pop rsi 00000001408879A6 pop rbx 00000001408879A7 retn ; 函数返回 00000001408879A7 ; --------------------------------------------------------------------------- 00000001408879A8 db 0CCh 00000001408879A8 ; } // starts at 1408875A4 00000001408879A8 DbgkpPostFakeThreadMessages endp
最新发布
08-15
<think>我们正在处理一个Windows内核函数的反汇编代码,需要将其转换为C代码。函数名为`DbgkpPostFakeThreadMessages`,其作用是为目标进程的线程发布虚假的调试消息。 函数签名(根据反汇编): __int64 __fastcall DbgkpPostFakeThreadMessages( PEPROCESS targetProcess, PDEBUG_OBJECT debug_object, PETHREAD Thread, PETHREAD *OutThread, PETHREAD *OutThread2) 参数说明: targetProcess: 目标进程(PEPROCESS) debug_object: 调试对象(PDEBUG_OBJECT) Thread: 线程(PETHREAD),如果为NULL,则遍历进程的所有线程 OutThread: 输出线程指针(PETHREAD*) OutThread2: 输出线程指针2(PETHREAD*) 函数流程: 1. 保存非易失寄存器,分配栈空间(480字节),并进行安全Cookie检查。 2. 保存参数到局部变量。 3. 初始化局部变量(清零APC状态结构和消息结构)。 4. 判断传入的Thread参数: - 如果Thread非空,则直接使用该线程,并增加引用计数。 - 如果Thread为空,则获取目标进程的第一个线程(遍历开始)。 5. 进入线程遍历循环: a. 如果当前线程为空,则跳出循环。 b. 如果前一个线程存在,则释放其引用。 c. 增加当前线程的引用计数。 d. 检查线程标志(系统线程、是否已插入进程线程列表等),如果不符合条件则跳过。 e. 获取线程的运行保护(RundownProtection),如果成功则挂起线程(PsSuspendThread)。 f. 初始化消息结构(DBGKM_APIMSG),根据情况设置消息类型(ApiNumber): 如果处理系统DLL(根据标志),则设置ApiNumber=2,并获取进程的Section句柄和基地址,附加到目标进程获取PE头信息(SizeOfHeaders和SizeOfImage)。 否则,设置ApiNumber=1,并保存线程的起始地址。 g. 调用DbgkpQueueMessage发送消息。 h. 如果消息发送失败,则根据之前的状态恢复线程(如果挂起则恢复)并释放资源,然后获取下一个线程继续循环。 i. 如果消息发送成功,并且是系统DLL模式,则额外发送系统DLL消息(DbgkSendSystemDllMessages_0)。 j. 获取下一个线程,继续循环。 6. 循环结束后,根据是否指定了输入线程(Thread非空)来设置输出参数(OutThread和OutThread2)。 7. 清理资源(释放线程引用),返回状态码。 注意事项: - 函数中使用了SEH(结构化异常处理)来处理访问目标进程内存可能出现的异常。 - 使用安全Cookie(__security_cookie)进行栈溢出保护。 我们将尝试用C代码模拟该函数的行为。由于涉及内核结构,部分结构体成员需要根据Windows内核头文件定义,但这里我们根据反汇编中的偏移进行注释。 由于代码较长,我们分步骤实现: 步骤1:定义必要的局部变量和结构。 步骤2:保存传入参数。 步骤3:线程遍历逻辑。 步骤4:处理每个线程(挂起、构建消息、发送消息、错误处理等)。 步骤5:清理和返回。 注意:由于反汇编代码中有很多硬编码偏移,我们在C代码中会使用相应的结构体成员。如果不知道确切的结构体,我们使用偏移量(通过注释说明)。 由于原函数较长,我们将其拆分为多个部分,并添加详细注释。 我们使用Windows内核中常用的NTSTATUS作为返回类型。 注意:以下代码是模拟的,不能直接运行,因为缺少内核结构定义,但可以用于理解原函数逻辑。</think>根据提供的汇编代码,我将`DbgkpPostFakeThreadMessages`函数转换为等效的C代码。以下是详细实现: ```c NTSTATUS DbgkpPostFakeThreadMessages( _In_ PEPROCESS TargetProcess, _In_ PDEBUG_OBJECT DebugObject, _In_opt_ PETHREAD Thread, _Out_ PETHREAD *OutThread, _Out_ PETHREAD *OutThread2 ) { // 栈变量声明 KAPC_STATE ApcState = {0}; DBGKM_APIMSG message = {0}; PETHREAD currentThread = NULL; PETHREAD previousThread = NULL; PETHREAD inputThread = Thread; BOOLEAN isSystemDllMode = FALSE; BOOLEAN isThreadParamNull = (Thread == NULL); ULONG threadStatus = 0; NTSTATUS status = STATUS_UNSUCCESSFUL; PVOID securityCookie = __security_cookie; // 保存当前线程 PETHREAD originalThread = KeGetCurrentThread(); // 引用计数标签 ULONG tag = 'DBgO'; // 0x4F676244 // 处理输入线程 if (Thread != NULL) { ObfReferenceObjectWithTag(Thread, tag); currentThread = Thread; } else { // 获取进程的第一个线程 currentThread = PsGetNextProcessThread(TargetProcess, NULL); } // 线程遍历主循环 while (currentThread != NULL) { // 释放前一个线程的引用 if (previousThread != NULL) { ObfDereferenceObjectWithTag(previousThread, tag); previousThread = NULL; } previousThread = currentThread; ObfReferenceObjectWithTag(currentThread, tag); // 检查线程状态 if ((currentThread->ThreadFlags & 0x400) || // 系统线程标志 !(currentThread->CrossThreadFlags & 0x2)) // 线程插入标志 { goto next_thread; } // 获取运行保护并挂起线程 BOOLEAN rundownAcquired = ExAcquireRundownProtection(&currentThread->RundownProtect); if (rundownAcquired) { threadStatus = 0xA; // 挂起状态标志 status = PsSuspendThread(currentThread, NULL); if (NT_SUCCESS(status)) { threadStatus |= 0x20; // 挂起成功标志 } } else { threadStatus = 0x12; // 运行保护失败 } // 初始化消息结构 RtlZeroMemory(&message, sizeof(message)); // 系统DLL处理模式 if (isThreadParamNull && !(threadStatus & 0x10)) { isSystemDllMode = TRUE; message.ApiNumber = 2; // 系统DLL模式 // 获取进程section信息 message.u.CreateProcess.FileHandle = DbgkpSectionToFileHandle(TargetProcess->SectionObject); message.u.CreateProcess.BaseOfImage = TargetProcess->Win32Process; // 附加到目标进程空间 KeStackAttachProcess(TargetProcess, &ApcState); // 在目标进程空间中获取PE头信息 __try { PIMAGE_NT_HEADERS ntHeaders = RtlImageNtHeader((PVOID)TargetProcess->Win32Process); if (ntHeaders) { message.u.CreateProcess.SizeOfHeaders = ntHeaders->OptionalHeader.SizeOfHeaders; message.u.CreateProcess.SizeOfImage = ntHeaders->OptionalHeader.SizeOfImage; } } __except(EXCEPTION_EXECUTE_HANDLER) { // 异常处理 message.u.CreateProcess.SizeOfHeaders = 0; message.u.CreateProcess.SizeOfImage = 0; } KeUnstackDetachProcess(&ApcState); } else { // 普通线程模式 isSystemDllMode = FALSE; message.ApiNumber = 1; // 标准线程模式 message.u.CreateThread.StartAddress = currentThread->Win32StartAddress; } // 发送调试消息 status = DbgkpQueueMessage( TargetProcess, currentThread, &message, threadStatus, DebugObject ); // 错误处理 if (!NT_SUCCESS(status)) { // 恢复线程状态 if (threadStatus & 0x20) { PsResumeThread(currentThread, NULL); } if (rundownAcquired) { ExReleaseRundownProtection(&currentThread->RundownProtect); } // 清理资源 if (message.ApiNumber == 2 && message.u.CreateProcess.FileHandle) { ObCloseHandle(message.u.CreateProcess.FileHandle, KernelMode); } } // 系统DLL特殊处理 else if (isSystemDllMode) { ObfReferenceObjectWithTag(currentThread, tag); inputThread = currentThread; DbgkSendSystemDllMessages(currentThread, DebugObject, &message); isSystemDllMode = FALSE; } next_thread: // 获取下一个线程 PETHREAD next = PsGetNextProcessThread(TargetProcess, currentThread); currentThread = next; } // 设置输出参数 if (Thread != NULL) { *OutThread = inputThread; *OutThread2 = previousThread; status = STATUS_SUCCESS; } else if (previousThread != NULL) { ObfDereferenceObjectWithTag(previousThread, tag); status = STATUS_UNSUCCESSFUL; } // 清理资源 if (Thread != NULL) { ObfDereferenceObjectWithTag(Thread, tag); } if (previousThread != NULL) { ObfDereferenceObjectWithTag(previousThread, tag); } // 安全校验 if (securityCookie != __security_cookie) { KeBugCheckEx(SECURITY_COOKIE_MISMATCH, ...); } return status; } ``` ### 代码解释: 1. **参数处理**: - 函数接受5个参数:目标进程、调试对象、可选线程、两个输出线程指针 - 当`Thread`参数为NULL,函数会遍历进程的所有线程 2. **线程遍历逻辑**: - 使用`PsGetNextProcessThread`遍历进程线程 - 对每个线程增加引用计数(`ObfReferenceObjectWithTag`) - 跳过系统线程(通过`ThreadFlags`检查) 3. **线程控制**: - 使用`ExAcquireRundownProtection`获取线程运行保护 - 通过`PsSuspendThread`挂起目标线程 - 错误使用`PsResumeThread`恢复线程 4. **消息构建**: - 两种模式:标准线程模式(ApiNumber=1)和系统DLL模式(ApiNumber=2) - 系统DLL模式需要附加到目标进程空间获取PE头信息 - 使用结构化异常处理(SEH)保护内存访问 5. **消息发送**: - 调用`DbgkpQueueMessage`发送调试消息 - 系统DLL模式额外调用`DbgkSendSystemDllMessages` 6. **资源清理**: - 正确管理对象引用计数 - 关闭创建的句柄 - 验证栈安全Cookie防止缓冲区溢出 7. **输出参数**: - 当指定具体线程,输出参数包含输入线程和最后处理的线程 - 当遍历所有线程,不设置输出参数 ### 关键数据结构: ```c typedef struct _DBGKM_APIMSG { ULONG ApiNumber; // 1=线程创建, 2=进程创建 union { struct { HANDLE FileHandle; PVOID BaseOfImage; ULONG SizeOfHeaders; ULONG SizeOfImage; } CreateProcess; struct { PVOID StartAddress; } CreateThread; } u; } DBGKM_APIMSG; ``` ### 安全机制: 1. **栈Cookie保护**: - 使用`__security_cookie`验证栈完整性 - 检测到破坏触发`KeBugCheckEx` 2. **引用计数**: - 所有对象操作使用带标签的引用计数 - 标签`'DBgO'`(0x4F676244)用于调试跟踪 3. **异常处理**: - 使用`__try/__except`保护跨进程内存访问 - 异常安全回滚资源
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值