PE文件解析——MS-DOS头解析
PE第一课——MS-DOS头解析
课堂笔记PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)
PE 文件的结构大约是这样的
用 010 随便打开一个 exe 文件,可以看到它的文件结构组成。
被标红高亮的部分就是 MS-DOS 头,他就是防止 PE 文件运行在 MS-DOS 系统下出现问题。
在 visual studio 当中可以去查看 _IMAGE_DOS_HEADER 结构体去查看 MS-DOS 头结构,结构体定义如下:
123456789101112131415161718192021typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // ...
《windows系统编程》——内存基础与相关结构
《Windows系统编程》——内存基础与相关结构 笔记
课堂笔记WINAPI学习在这堂课也有点摸清楚一些规律了,WINAPI 中的一些结构体,除了定义结构体本身以外还会定义它的指针类型,一般在该变量类型名前加上前缀 lp(LP)。
GetSystemInfoGetSystemInfo 函数用于获取系统信息,传入参数位 SYSTEM_INFO *,没有返回值,获取的系统信息通过 SYSTEM_INFO 结构体返回,结构体定义如下。
123456789101112131415161718typedef struct _SYSTEM_INFO { union { DWORD dwOemId; // Obsolete field...do not use struct { WORD wProcessorArchitecture; WORD wReserved; } DUMMYSTRUCTNAME; } DUMMYUNIONNA ...
楔子
仅当我对前两年时间的人生总结吧。。。
Linux Signal机制
今天吧,来具体了解一下 Linux 的一个 signal 机制。
问题引入起因在于我向老师抛出一个问题,在 子进程调用 execve 并重定向标准输出为管道时,父进程从管道读取数据时,采用 read 函数去读取,但是会发现一个问题。就是读和写不太能同步,即使程序退出,管道中还残留数据,如果管道中的数据还有,那么我读入不完整,如果没,则继续调用 read 会挂起父进程无法退出,一直想不到有效的办法解决。
请教老师之后,老师推荐我学学 signal 机制,并给我看了一个例程,例程大致简化一下是这样的:
123456789101112131415161718192021222324252627#include<stdio.h>#include<unistd.h>int k;void func(int sig){ k=0;}int main(){ pid_t pid=fork(); if(pid<0){ write(2,"fork error!\n",12); ...
Hook专题6- hook
今天学一学 hook 专题最后一章,也就是 无痕 hook。
学习笔记这个无痕 hook 是相对无痕,而不是没有方法检测。因为前面的五种 hook 方法可以在完整性检查中直接被检测出来,但是无痕 hook 是通过硬断+VEH的方式 hook 的。内存完整性检查能完美 bypass。
硬件断点在之前的 kxbook 中讲过,是通过 DR 寄存器来实现的。
DR寄存器的用途DR0-DR3DR0到DR3被称为“调试地址寄存器”或“地址断点寄存器”,它们非常简单,其中仅包含断点的线性地址。当该地址与指令或数据引用匹配时,将发生中断。调试寄存器DR7可用于对每个断点的条件进行更细粒度的控制。因为寄存器需要填充线性地址,所以即使关闭分页,它们也可以正常工作。在这种情况下,线性地址将与物理地址相同。
由于这些寄存器中只有4个是可用的,因此每个线程最多只能同时具有4个断点。
DR4-DR5DR4和DR5被称为“保留的调试寄存器”。尽管它们的名称中有“保留”字样,但实际上却不总是保留的,仍然可以使用。它们的功能取决于控制寄存器CR4中DE字段的值。在启用此位后,将启用I/O断点,如果尝试 ...
Hook专题5-VEH hook
学一学 hook 专题,今天是 VEH hook。
学习笔记今天学了比较新的一个 hook 的姿势:利用异常处理去hook。
前置芝士SEHSEH 即 结构化异常处理(Structure Exception Handler),是Windows操作系统提供的强大异常处理功能。当程序执行过程中发生异常时,零环会使用KiDispatchException判断是否有内核调试器。如果没有调试器,零环转交给三环的KiDispatchException,开始找是否有异常处理程序(SEH、VEH)。如果已安装,会调用异常处理程序进行处理
异常处理流程:异常产生->调试器->VEH->SEH->TopLevelEH->调试器
SEH有很多缺点(基于线程、基于栈、处理优先级低)等等。
VEH向量化异常处理(Vectored Exception Handler),我们可以用AddVectoredExceptionHandler函数注册自定义的VEH。当捕获到异常时,我们会拿到一个_EXCEPTION_POINTERS类型的参数。而这个参数的成员ContextRecord ...
Hook专题4-hotfix hook
学一学 hook 专题,今天是 hotfix hook。
学习笔记hotfix hook和 inline hook差不多,但是有利用条件,一是被hook的位置附近有空内存,那么可以直接把被 hook 函数的代码先短跳到附近内存,然后由这个内存跳转到我们自己的函数,这样的话就不需要频繁地装钩卸钩了。
也直接试试吧
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172#include <stdio.h>#include <Windows.h>typedef int(WINAPI * fnMessageBoxA)( _In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType); ...
Hook专题3-virtual hook
学一学 hook 专题,今天是 virtual hook。
前置芝士早就听说 C++ 因面向对象而闻名,然而我们平时在算法比赛中使用的 C++ 却几乎没有面向对象的内容,C++ 的类中有一个非常厉害的东西叫虚函数,C++中的虚函数的作用主要是实现了多态的机制,多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。
这是一种泛型技术,所谓泛型技术就是试图使用不变的代码来实现可变的算法。比如 平常的排序,排序的东西种类有很多,我们如果都为此写一个 sort 函数,那太过于麻烦,泛型技术就解决了这种麻烦,比如 std::sort,它可以通过自定义比较规则的方式来实现多种类型的数据都能使用这个 std::sort,只要你为数据类型重载了小于号即可。
test12345678910111213141516171819#include <iostream>using namespace std;class Base {public: virtual void f() { cout << "Bas ...
Hook专题2-IAT hook
学一学 hook 专题,今天是 IAT hook。
课堂笔记IATIAT 就是 Import Address Table,导入地址表,其实感觉跟 Linux ELF 的全局偏量表(GOT)是一样一样的,IAT hook 原理就很简单,我们只需要改写这个表到我们自己的函数,如果需要执行原函数的逻辑,那么我在 hook 的时候保存 IAT 的初始值,直接 call 过去即可。
hook步骤我们需要分析 PE 文件头,先拿到 IAT 表的一个位置,然后拿到该函数的偏移,去改写它。
那么我们先获取一个 PE DOS HEADER,使用 API GetModuleHandle 第一个参数传 NULL 可以获取该 PE 文件的 DOS 头。再从这个 DOS 头里面获取 NT 头,从 NT 头拿扩展头。有了扩展头之后,我们就能找到 IAT 了。
因为一个 PE 文件,他可能有很多模块,也就是很多的 IAT,因此我们后面需要遍历所有的 IAT,找到了 MessageBoxA 进行一个替换。
dllmain.cpp
123456789101112131415161718192021222324252 ...
Hook专题1-inline hook
学一学 hook 专题,今天是 inline hook。
课堂笔记hook概念hook 就是钩子,是一种劫持技术,把原本执行的函数替换,替换为我自己的一个函数。当然在学 pwn 的时候,也有接触过 hook,就是 malloc_hook 和 free_hook。这些 hook 本意是为了开发者方便调试自己编写的 malloc 或者 free 函数去使用的,比如我自己写了一个 free 函数,我想测试一下性能,那我直接 __free_hook=myfree 就可以测试了,但是没想到就一直被打,直到 glibc 2.34 版本,这些 hook 被彻底删除。
inline hook的用法inline hook(内联钩子),是指在函数的代码当中的一个地方(一般是代码开头),写上跳转指令,跳转到我们执行的函数,跳转完成之后,为了保持函数正常运行我们可能会释放钩子(unhook),把程序放回原来的位置,或者是直接执行完自己的代码就结束。
无条件跳转指令编码一般,无条件跳转指令编码为 E9 + 32位小端序整型(根据 %rip 寄存器寻址),比如 E9 05 00 00 00 表示跳 ...