自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(35)
  • 收藏
  • 关注

原创 InlineHook的原理与做法

第一步先保存所有的寄存器和Eflag 然后这里我们拿到我们想要的数据 比如函数的参数和函数返回地址 然后将保存的寄存器和eflag出栈 然后模拟提升栈顶的操作因为原本函数的这个操作被我们nop掉了 然后使用jmp跳转到我们记录的地址即可。注意跳转地址的计算方式是 跳转到目标地址减去要进行跳转函数的地址再减5(减5的原因是jmp指令长度为5)简单来说InlineHook流程 就是使用jmp跳转到我们自己写的代码区域执行我们自己写的代码。重点就是将原本保存的指令重新写入到函数的起始位置。

2025-06-02 19:29:43 433

原创 劫持进程注入

劫持进程注入和远程线程注入的区别就是 远程线程注入是向一个正在运行中的进程注入 而劫持进程注入则是自己打开一个进程(以挂起的方式) 然后再进行注入的操作。这样做的原因是当进程在挂起的状态时他的所有线程都是处于未启用的阶段 这样就可以避免目标进程的反注入线程的检测 从而使得注入的操作成功率更高。注意目标的进程句柄会通过PROCESS_INFORMATION这个结构体传递。第用CreateProcessA函数以挂起的状态打开我们的目标进程。CREATE_SUSPENDED是挂起的方式打开进程。

2025-06-01 21:59:39 317

原创 远程线程注入

这里要注意一下为什么在我们的进程可以直接使用LoadLibiary的地址呢 因为这个地址是所有进程共享来的 我们得到的地址和他的地址是一样的。第三步 使用WriteProcessMemory函数在指定进程写入LoadLibiary的参数pDllPath。第二步 使用VirtualAllocEx在指定的进程分配内存。第一步 使用OpenProcess获取目标进程的句柄。注入简单来说就是让别人的程序执行 你想要让他执行的dll。他和CreateThread的区别就是三个参数的形式。

2025-05-31 21:32:26 298

原创 WIN32-内存管理

他与malloc和new的不同在于VirtualAlloc是真正意义上的开辟的一片内存 而且它可以为开辟出来的内存指定属性第一个参数为需要开辟内存的首地址 可以填NULL如果为NULL则由自动为你自动分配第二个参数为你想要开辟内存的大小第三个参数为你想要开辟的内存属性这里我们就写第四个参数为开辟内存的权限 分配动态内存时,flProtect参数必须或。

2025-05-31 21:06:26 264

原创 WIN--文件读写

CreateFile这个API是文件读写的核心下面我们来看看他的使用方式第一个参数 如果我们想要创建或者打开的是一个文件那么这里就写文件的路径 如果是其他IO设备就写设备名第二个参数 是请求对文件或设备的访问权限 可以为第三个参数 请求的文件或设备的共享模式(其他进程对该文件权限)我们通常写为FILE_SHARE_READ(其他进程可读)第四个参数 我们通常写为NULL*第五个参数(重点) 对存在或不存在的文件或设备执行的操作 下面为这个参数的不同情况2。

2025-05-26 17:28:41 867

原创 WIN32---创建线程

这个函数的第一个参数为选择是否继承我们通常为填为NULL不继承 第二参数为你想要为这条线程开辟栈区的大小 通常填写为0自动设置为和创建这条线程的线程的大小 第三个参数为这条线程。你要执行函数的地址传入函数名()即可 第四个参数为你所要执行函数的参数 第五个参数为接收新线程标识符的变量的地址。然后GetExitCodeThread这个函数的返回值如果为259表示线程正在进行如果为其他数值表示正常或者异常退出的数值。参数是我们想要挂起的线程的句柄。参数是我们想要挂起的线程的句柄。

2025-05-25 21:38:51 316

原创 进程通信-内存共享

这个函数可以创建或者打开一个文件映射 当第一个参数为INVALID_HANDLE_VALUE时就是创建一个文件映射 第二个参数选择是否继承 第三个参数是创建的这个文件的权限 第四个为最大尺寸的高32位通常为0第五个是低32位 我们通过改低32位的数值即可控制文件的大小 最后一个参数为你这个文件映射的名称(另一个程序读取的时候会用到它)这里我们要写两个程序 第一个程序用来创建一片内存 第二个程序用来读取那片内存。下面来写第二个程序----读取第一个程序创建的内存。第二步还是将文件映射转换到内存中。

2025-05-25 18:25:33 197

原创 跨进程读写

目标数据的地址 我们第一个程序输出了M_data的地址所以这里直接写即可(注意要强转一下) 第三个参数是一个指针用于传出读取到的数据 第四个参数是你要读取数据的字节数 第五个是一个指针用于传递实际读取了多少可为null 然后进行循环读取即可。函数进行读取 这个函数的第一个参数为句柄 第二个参数为你想要读取内存的起始地址(我们设置了固定基址所以为0x400000)第三个为读取到的数据所传出来的容器第四个参数为你想要读取的字节个数 第五个参数为你实际读取了多少个字节。---读自己的内存 第一步使用。

2025-05-24 21:29:34 122

原创 进程的挂起与回复 以及函数指针

进程的挂起和回复函数 在动态库ntdll.dll中 所以我们要先加载这个动态库 然后获取我们要使用的这两个函数的地址 并使用函数指针指向他们从而调用函数。第二行我们相当于声明了一个函数指针的变量 变量名字为sus 变量类型为DWORD(WINAPI*)(HANDLE);第一行我们使用typedef定义了一个类型 名字为ResumeProcess 他的类型是。加载动态库的方式 使用函数LoadLibraryA获取我们目标函数在动态库中的地址。第三行使用我们刚刚定义的类型名字声明一个变量。

2025-05-24 18:51:58 90

原创 WIN32创建进程CreateProcessA 以及子进程和父进程

第一步我们使用代码打开一个成员 然后获取进程快照 并遍历当前的所有进程 找到了对应的进程名我们就输出 然后在代码尾部下断点 可以看到输出的父进程pid去任务管理器中对比pid可以看到是我们这个项目名.exe运行的它 所以我们这个项目.exe就是父进程 我们打开的这个PETool就是子进程。LPSECURITY_ATTRIBUTES lpProcessAttributes,//指向 SECURITY_ATTRIBUTES 结构的指针,指定新进程的安全属性。

2025-05-24 17:49:55 236

原创 重定位表 IMAGE_OPTIONAL_HEADER->IMAGE_DATA_DIRECTORY->_IMAGE_BASE_RELOCATION

修补的方式是取后三位加上VirtualAddress就可以得到一个RVA 进而加上IMAGEBASE就可以定位到需要修正到的地址 也就是修正后的地址。这个结构体是IMAGE_OPTIONAL_HEADER中的最后一个成员数组的第五个元素。第一个成员先不做解释 第二个成员是表示当前块的大小也就是三个成员的大小总和。数组的第一个成员是这个 他的16进制第一位为3所以他是需要修补的。第三个成员是一个word类型的数组 里面存储着需要修补的偏移量。比如这个表格这是两个块 怎么判断修补的偏移位置呢。

2025-05-22 19:35:21 294

原创 IMAGE_OPTIONAL_HEADER->IMAGE_DATA_DIRECTORY->IMAGE_EXPORT_DIRECTORY和IMAGE_IMPORT_DESCRIPTOR

这个导入表的结构我们可以简单将他看作是一个DWORD类型的数组 有4个成员 当他的最高位为1的时候低31位为他的导出序号 否则OriginalFirstThunk和FirstThunk会重新指向一个结构体。6-AddressOfNames 存储着一个RVA 此RVA指向了一个数组 这个数组的元素个数由NumberOfNames来决定 这个数组里面存储的是各个导出函数名的RVA。// 指向一个包含所有导出函数地址的RVA数组的RVA。// 指向一个包含函数序号的RVA数组的RVA。// 导出函数的总数。

2025-05-21 21:44:28 231

原创 PE文件之IMAGE_SECTION_HEADER

是一个char类型的数组他的作用是记录它所在这片节区的名称 IMAGE_SIZEOF_SHORT_NAME是一个定义好的宏 数值为8。IMAGE_SECTION_HEADER在文件中是有多个的 他的数量由IMAGE_FILE_HEADER中的NumberOfSections成员来决定。节的属性下面是他的数值所对应的属性。2. 0x08 DWORD VirtualSize:表示的是当前节区所占内存的实际大小。

2025-05-17 21:37:57 329

原创 PE文件之_IMAGE_NT_HEADERS中的_IMAGE_OPTIONAL_HEADER

这是程序开始执行的地方。对于DLL,这可能是DllMain函数的起始位置。对于DLL,这可能是DllMain函数的起始位置。结构的数组,每个结构提供了指向PE文件中特定数据块(如导入表、导出表、资源等)的位置和大小的信息。: 所有头部(包括DOS头、PE头、节表)加起来按照文件对齐后的大小。这意味着,在文件开头到第一个节之间的总大小。则表示这是一个64位的PE文件。字段定义了这些目录项中有多少是实际有效的或被使用的。来对齐的,包含了所有的头、节以及未使用的空间。表示这是一个32位的PE文件,而。

2025-05-17 20:13:58 439

原创 PE文件之_IMAGE_NT_HEADERS中的_IMAGE_FILE_HEADER

当文件为32位的时候SizeOfOptionalHeader的大小位0xE0 文件为64位的时候SizeOfOptionalHeader的大小位0xF0。第六个成员SizeOfOptionalHeader是拓展PE头(IMAGE_OPTIONAL_HEADER)的大小。第二个成员NumberOfSections为PE文件中节(IMAGE_SECTION_HEADER)的数量。下面来看 Characteristics数值对应的文件属性(相应数据位为1文件具有的属性)第四个成员和第五个成员不必了解。

2025-05-17 18:51:03 419

原创 PE文件之 _IMAGE_NT_HEADERS

所以实际的偏移量和数值是一一对应的 我们先走到距离文件头0x3c的地址 并解引用赋值给dwoffest 然后定义一个DWORD类型的指针来指向。第三个成员是可选的拓展PE头 有两种一种是32位一种是64位 OptionalHeader指向了_IMAGE_OPTIONAL_HEADERS。第二个成员是标准PE头 FileHeader成员指向了标准PE头_IMAGE_FILE_HEADER。IMAGE_NT_HEADERS有两种类型一种是32位一种是64位 他们所占用的大小是不同的。

2025-05-17 17:51:38 252

原创 C逆向之结构体指针寻址

通过打印并对比内存发现 a+1输出的结果是结构体的首地址加4 原因是 指针的类型是int类型 加1实际上是加了一个sizeof(int)也就是4 通过查看反汇编发现确实如此 但是结构体的成员有char类型的如果我们都用int类型的指针去偏移 会偏移到错误的位置 所以我们应该定义char类型的指针去偏移寻找成员。先看一下源代码 定义了一个结构体 下面来分析 当找到结构体的首地址时 如何通过偏移 找到结构体里的每一个成员。

2025-05-16 19:50:06 727

原创 C语言HEADER文件写入和读取

使用char*来创建容器的原因是可以更精准的操作每个字节。然后查看内存可以看到数据和winhex中的一样。

2025-05-15 19:59:59 193

原创 PE文件之_IMAGE_DOS_HEADER

IMAGE_DOS_HEADER结构是面向与16位程序的 所以对于现在的32/64位程序 这个结构体中的成员只有两个是有用的 其余均为垃圾数据可以随意更改不会影响原程序 这个结构体的大小位0x40。再回到winhex中查看在_IMAGE_DOS_HEADER到_IMAGE_NT_HEADERS这两个结构体之间还有一段数据 这些数据是编译器生成的数据 也是垃圾数据可以随意更改不影响程序的运行。5A4D对应的是MZ 00000100对应的是PE标记相对于文件头(5A4D)的偏移。

2025-05-15 19:04:08 198

原创 PE文件--什么是PE文件

为什么偏移3C呢可以看这张图 当我们找到了文件头之后 偏移0x3c就可以到signature这个PE文件的标记位置从而进行判断。将一个.exe文件拖入到winhex中查看 先找到标记头4D 5A 再去找从4D 5A偏移3C的位置。记住三个关键数 4D 5A, 3C , 50 45 这三个数位置匹配 那么就成功找到了PE文件。但是一个文件是这三个格式其一并不代表他就是PE文件 下面是判断PE文件的直接方法。50 45那么说明这个文件为PE文件。

2025-05-15 18:12:23 178

原创 C逆向之位运算 shl左移 sar有符号右移 shr无符号右移

左移语法为<<后面是几就是左移几位 同理>>右面是几就向右移动几位。左移在汇编中对应的指令为shl 右移在汇编中的指令为sar。

2025-05-12 21:18:56 734

原创 C逆向之浮点数返回值

开始分析汇编指令 第一步call指令调用函数func 紧挨着call指令是fstp指令 可以知道fstp是给f赋值的一个指令 所以我们可以猜测到浮点数的返回值 通过栈顶传递出来 接着向下走。先了解一下浮点数的指令。

2025-05-12 20:02:23 872

原创 C逆向之嵌套函数

现在已经进入了func2函数之中 第一片指令是开辟栈区的过程 第二片指令是将新开辟的栈初始化 执行完第一片和第二片指令后栈区为。通过分析之后发现第三片指令的作用是 将1放到最新开辟的栈区 然后进行了一步交换的操作 之后变为了下面这样。第一步执行这三条指令 将1和2先后压入栈 使用call指令后将call指令的下一个地址也压入了栈。第三片指令的作用是将ebp向下2个位置和3个位置的数值压入栈 显然是我们的1和2 所以栈区变为。先看一下正向的代码 是一个简单的交换输出函数。接下来分析反汇编代码。

2025-05-11 17:35:01 929

原创 C逆向之有返回值和参数的函数

前三条指令用于开辟栈区 接下来三条将易变寄存器压入栈 接下来四条指令将新开辟出来的栈区初始化 再下面的指令前两条为 定义局部变量 分别为a和b 第三四五条进行运算将结果存入变量c第六条将c存入寄存器 这时我们应该有个疑问了 明明eax和c的数值已经相等了为什么还要赋值一遍呢 我们可以猜测eax就是用来传递返回值的 最后几行是进行返回操作。看call指令的下一条指令就可以知道 eax确实是用来传递返回值的。上面是源代码 下面是汇编代码。现在开始一步步的分析汇编代码。

2025-05-10 20:42:32 208

原创 C语言逆向之空函数

ecx数值变为10 eax的数值变为CCCCCCCC 接着重复执行stosd ecx(10)次 也就是将edi当前位置到edi加10*4的地址全赋值为CCCCCCCC。所以栈区变为下面这个样子 esp的数值先为0019F7AC后变为0019F7A0 edi的值变为0019F7AC。惊奇的发现 变回了执行call指令之后的栈 然后进行一个ret 恰好回到了 call指令的下一个地址。第一步call 指令(将当前地址的下一个地址压入栈并调换到call指令所指定的地址)接着走 将EBP的数值压入栈区。

2025-05-10 18:57:04 1038

原创 堆栈 PUSH POP CALL RET

栈结构在内存管理中扮演重要角色,类似于C++中的stack数据结构。在x86汇编中,EBP指向栈底,ESP指向栈顶,EBP到EIP之间的内存为当前线程占用。PUSH操作将数据压入栈,可分解为减少ESP和移动数据到栈顶两步。POP操作从栈顶取出数据,并增加ESP。CALL指令跳转到指定地址前,会将返回地址压入栈。RET指令则将栈顶值赋给EIP,并出栈,实现函数返回。这些操作共同维护了程序执行流程和函数调用的正确性。

2025-05-09 20:33:47 120

原创 STOS MOVS REP

11

2025-05-09 19:33:24 168

原创 JCC有条件跳转

JNP/JPO:奇偶标志为0时跳转(NP = Not Parity,PO = Parity Odd)。JNE/JNZ:不等于/不为零时跳转(NE = Not Equal,NZ = Not Zero)。JAE/JNB:高于等于/不低于时跳转(AE = Above or Equal)。JBE/JNA:低于等于/不高于时跳转(BE = Below or Equal)。JE/JZ:等于/为零时跳转(E = Equal,Z = Zero)。JA/JNBE:高于/不低于等于时跳转(A = Above)。

2025-05-08 21:09:36 247

原创 EIP JMP CMP TEST

作用: 用目标操作数减去源操作数 但是不影响两个操作数 影响的是标志位 通过标志位来判断对比结果。作用:将两数进行AND运算 也是影响标志位从而进行判断。EIP寄存器中所储存的是 当前要执行的指令的地址。jmp(无条件跳转)可以理解为c语言中的goto。通过反汇编可以更清晰的看到jmp语句的作用。语法:cmp 目标操作数, 源操作数。语法:test 目标操作数, 源操作数。

2025-05-08 21:00:32 136

原创 标志寄存器EFLAGS

个人理解就是 当前运算发生超出范围的时候cf就会为1否则为0 而这个范围就要看你要操作的寄存器了 如果是8位 如果运算结果大于0xff或者小于0x00 那么CF会变为1 16位的话运算结果大于0xff或者小于0x00CF会变为1 32位也同理。再比如执行这两条指令 现在只涉及到ah这个范围 所以只需要关注ah的最低8位bit即可 也就是它本身的整体 所以经过两个指令后 AF变为了1。当运算结果的最低字节二进制数中1的个数为偶数PF置1,反之为0。当前运算涉及到的寄存器的范围。

2025-05-08 19:45:31 175

原创 指令-LEA

在c语言中可以更直观的看出mov和lea的作用 mov将1234数值赋值给变量a 也就是把1234放到a所在的内存地址 然后*p=&a 对应lea这条指令 也就是将a的地址赋值给p。那么执行第一条指令后eax的数值为0x0019f7f8 执行第二条执行后eax的数值为1234。r为register的缩写也就是寄存器 m为memory也就是内存。经过下面这条指令之后eax的数值变为了0x0019F7F4。假设0x0019f7f8这段内存地址所存的数值为1234。3.[reg+立即数]

2025-05-07 21:08:43 167

原创 汇编--内存

比如eax是0x12345678 而0x12345678这个地址存的数值为0xFFFFFFFF 那么执行完之后 ecx的数值变为0xFFFFFFFF。具体是啥不清楚 []中存放的是地址 []中不仅可以存放立即数 也可以存放寄存器 此时的寄存器我们可以将它看作是一个变量。ptr代表的是指针也就是说加了ptr之后就要进行内存地址相关的操作了ds:表示的是一种内存段。下面这段代码是将eax所存的数值的地址的数值 复制到ecx中。4.[reg+reg*{1,2,4,8}+立即数]3.[reg+立即数]

2025-05-07 20:00:46 134

原创 汇编-16/8位寄存器

可以看到eax寄存器的变化是 0x12345678------0x12340000------0x12341200-------0x12341234。简单来说8位寄存器是16位寄存器的一部分16位寄存器又是32位寄存器的一部分。像他们的名字一样 32位寄存器的数据宽度就是32位二进制数最多8位16进制数。通过断点调试观察寄存器的变化直观的理解了不同位寄存器之间的关系。同理16位寄存器数据宽度为16位二进制数 最多4位16进制数。8位寄存器数据宽度为8位二进制数 最多2位16进制数。

2025-05-05 21:26:17 122

原创 汇编-32位寄存器

------跟0xcc老师学习逆向的第1天。在x64dbg中选中一行 右键然后点击汇编 就可以修改当前的汇编指令然后步过 在右侧栏可以直观的看到寄存器的变化。作用:将数字拷贝到寄存器中 或者是将一个寄存器拷贝到另一个寄存器。可以通过VS直观的看到寄存器数值的变化。但并不是所有CPU都有64位寄存器。分为8 16 32 64寄存器。寄存器是CPU存储数据的地方。MOV 寄存器,寄存器。MOV 寄存器,数字。

2025-05-05 20:14:22 116

原创 汇编基础-位运算

定义:将二进制数的每一位都进行取反 0变1 1变0。定义:两个对应位置的数不一样结果为1 不然结果为0。在c语言中的符号是~ 在汇编语言中的指令是NOT。在c语言中的符号是^ 在汇编语言中的指令是XOR。在c语言中的符号是| 在汇编语言中的指令是OR。在c语言中的符号是& 在汇编语言中是AND。定义: 两个数都为1结果才为1 不然都为0。定义:两个数中有一个为1结果就为1。下面为示例 可以断点查看内存。

2025-05-05 19:02:43 126

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除