上一步阐述了如何使用代码替换功能对付变化位置的数据地址,但这种方法往往不能达到预期的效果,所以我们需要学习如何利用指针,在本关的Tutorial.exe窗口下面有两个按钮,一个会改变数值,另一个不但能改变数值而且还会改变数值在内存中存储的位置...接下来我们将找到内存中的基址,为什么要找指针,在前面的教程中,如果各位细心观察的话就会发现 在笔者截图中的出现地址和你的地址并不相同。...也就是说,这些地址是一直在变化的,我们把它叫做动态地址,我们必须寻找到该动态地址的基址,并以此来保证唯一性。...;至此读者通过双击打开mov [edx],eax则可看到当前汇编指令的详细输出情况,寄存器EDX后面并没有任何偏移地址,此时读者只需要关注EDX寄存器的值,因为该值保存有指向下一个区域的内存地址,将地址...01A252A8复制到剪辑版中;将新地址以十六进制格式搜索四字节,并可输出一个绿色的"Tutorial-i386.exe"+2566B0没错,该地址就是一个基地址,此地址在程序重启后也不会发生任何的变化
上一步阐述了如何使用代码替换功能对付变化位置的数据地址,但这种方法往往不能达到预期的效果,所以我们需要学习如何利用指针,在本关的Tutorial.exe窗口下面有两个按钮,一个会改变数值,另一个不但能改变数值而且还会改变数值在内存中存储的位置...接下来我们将找到内存中的基址,为什么要找指针,在前面的教程中,如果各位细心观察的话就会发现 在笔者截图中的出现地址和你的地址并不相同。...也就是说,这些地址是一直在变化的,我们把它叫做动态地址,我们必须寻找到该动态地址的基址,并以此来保证唯一性。...; 至此读者通过双击打开mov [edx],eax则可看到当前汇编指令的详细输出情况,寄存器EDX后面并没有任何偏移地址,此时读者只需要关注EDX寄存器的值,因为该值保存有指向下一个区域的内存地址,将地址...01A252A8复制到剪辑版中; 将新地址以十六进制格式搜索四字节,并可输出一个绿色的"Tutorial-i386.exe"+2566B0没错,该地址就是一个基地址,此地址在程序重启后也不会发生任何的变化
2.上图可以看到有两条汇编指令,而前面的计数器一直在增加,说明有时钟一直在访问这个地址,我们以第2条汇编指令为例,点击反汇编当前地址在XOR指令上按下F5下断点,其中mov eax,[esi+5560]...则表示将当前阳光数量赋值给EAX寄存器,我们可以看到右侧寄存器窗口eax=32,其中的32正好就是阳光的十六进制表示形式,注意mov eax,[esi+5560]这条指令,观察该指令在注入前与注入后会有什么变化...originalcode之前写入以下汇编代码,其中push eax,pop eax分别是压栈与出栈,因为我们要使用EAX寄存器暂存数据,此时必须要将原始的EAX寄存器里面的内容进行保存,在代码执行完毕以后必须通过...POP指令归位,否则会导致程序异常或堆栈失衡,mov eax,[esi+5560]则表示将[esi+5560]中的数据取出来,此处就是阳光的数量。...,并且类型为映像的,这里还需要看后面的模块一定要是植物大战僵尸文件里的模块,此处我找到了一个内存地址 0B4CF000,双击即可跳转到相应的位置,这里我们不能选择02CA9000这个内存地址,因为这个地址是
2.上图可以看到有两条汇编指令,而前面的计数器一直在增加,说明有时钟一直在访问这个地址,我们以第2条汇编指令为例,点击【反汇编当前地址】在XOR指令上按下【F5】下断点,其中【mov eax,[esi+...5560]】则表示将当前阳光数量赋值给EAX寄存器,我们可以看到右侧寄存器窗口【eax=32】,其中的32正好就是阳光的十六进制表示形式,注意【mov eax,[esi+5560]】这条指令,观察该指令在注入前与注入后会有什么变化...,此时可以在【originalcode】之前写入以下汇编代码,其中【push eax,pop eax】分别是压栈与出栈,因为我们要使用EAX寄存器暂存数据,此时必须要将原始的EAX寄存器里面的内容进行保存...8.此时我们通过代码注入器,向程序中注入代码,即可实现产出阳光,到此还没有结束,下方的注入代码有一个变量【13DBD880】这个动态内存地址每次启动游戏都会发生变化。...6.最后附一张注入成功后的效果图,如下所示: 通过手工计算偏移地址 首先我们思考一个问题,为什么我们需要手工计算偏移地址,CE找不开心吗?
这次,GCC老老实实的将if语句生成了汇编代码。 可能有人会质疑:为什么要使用__asm__("":::"memory")向GCC声明内存发生了变化?...但我们以后的例子会更加清楚的表现这一点。 关于为什么内联汇编__asm__("":::"memory")是一条声明内存改变的语句,我们后面会详细讨论。...如果你用了它,则是向GCC声明“不要动我所写的Instruction List,我需要原封不动的保留每一条指令”,否则当你使用了优化选项(-O)进行编译时,GCC将会根据自己的判断决定是否将这个内联汇编表达式中的指令优化掉...括号括住的部分是一个C/C++表达式,用来保存内联汇编的一个输出值,其操作就等于C/C++的相等赋值cr0 = output_value,因此,括号中的输出表达式只能是C/C++的左值表达式,也就是说它只能是一个可以合法的放在...,或使用"g","r"等约束让GCC为其选择寄存器,GCC已经知道哪个寄存器内容发生了变化,所以这么做没有什么意义;我也作了相关的试验,没有发现使用它会对GCC生成的汇编代码有任何影响,至少在i386平台上是这样
相反,如果信号量的值等于0,该进程就会等待,直到有其它程序释放该信号量。释放信号量的过程就称为V操作,通过增加信号量的值,唤醒正在等待的进程。 注: 信号量,这一同步机制为什么称为PV操作。...当然了,结构体的变化必然导致操作信号量的函数发生设计上的改变。 3 如何获取和释放信号量 前面我们已经知道,信号量实现在内核发展的过程中发生了更变。所以,其获取和释放信号量的过程必然也有了改变。...如果eax寄存器中的值大于0,说明没有进程在等待这个信号,则跳转到标号1处开始执行。...使用加载有效地址指令lea将寄存器ecx中的值的地址加载到eax寄存器中,也就是说把变量sem->count的地址(因为count是第一个成员,所以其地址就是sem变量的地址)加载到eax寄存器中。...至于两个pushl指令把edx和ecx压栈,是为了保存当前值。因为后面调用__up()函数的时候约定使用3个寄存器(eax,edx和ecx)传递参数,虽然此处只有一个参数。
$0, %eax 好了,这里也只是感受一下,具体Intel(X86-64)的汇编风格,我后面会在c语言专辑里面详细写到(结合我们平时的c语言程序类具体分析!)...那么为什么CPU在运行的时候要有寄存器这么东西呢,我之前看过一段话,解释的比较到位: 想象CPU是一个圈一直在运转,然后寄存器里面有大量的指令,这些指令不知道从哪里来的,但是一般情况下我们的CPU在计算我们的程序...,内存并不稳定并且很慢,所以就要想办法能不能找到一个临时空间保存一下,这就是为什么会诞生寄存器。...CPSR和SPSR都是程序状态寄存器,其中SPSR是用来保存中断前的CPSR中的值,以便在中断返回之后恢复处理器程序状态;CPSR是当前程序状态寄存器的意思,SPSR是程序状态保存寄存器,这里我在网上看到一个非常通俗易通的解释这两个寄存器的用法...,但是这个时候当时的状态已经被清理掉了,这个时候我们就可以用SPSR把原来那个状态保存,这样当状态在发生改变的时候,要还原就可以去SPSR里面读取之前那个状态,这就是它们之间的关系,就类似有一个A的变量
L0003: mov eax, 1 L0008: inc eax L0009: cmp eax, 0xa Release较Debug的变化是:JIT知道在当前方法上下文中,len是个局部变量,且始终不会改变...因此,在往后对循环体的编程中,若代码主体不会改变循环变量的值的话,那么尽量可以在循环体中创建一个副本来去使用,这样对性能可以有效的提升。...介绍完通过将循环变量直接存储在寄存器中的方式所带来的性能提升后,下面我将介绍因为这种jit优化的方式所带来的潜在性Bug。...第二条线程将改变i的值以让它小于等于0 按照正常逻辑来走,第二条线程一定会执行改变值的代码,因此方法在运行后始终会终止(会因主线程跳出循环的结束而结束)....在第二段中,我已经举例介绍了这种优化,这取决于JIT是否能跟踪到代码对变量i的更改,若JIT通过中间形式解析后能够跟踪到对循环变量的修改,则对循环变量将不会使用寄存器来进行优化。
但是我在任务管理器里面始终找不到 QQpinyin 的进程,可能是程序加载了 QQPinYin 的模块,而这个模块一直在循环 ReadFile (这难道是键盘记录嘛,不懂不懂,求大佬赐教)。...这里我选择寄存器,因为如果存在栈中的话你需要不断的改变 esp mov [esp],某个寄存器 并且不断调用这样的语句对栈的内容进行赋值,操作简单但是过于繁琐。...把该地址放在 ROP 链的首端,也就是把 0022FD54 的值覆盖为 649b11ec(具体怎么覆盖,大家可以自行计算),顺便手动把 OD 中这几个寄存器的值都改变一下(esp 的值不能动)如图: ?...pop esi,我们可以随便给 esi 弹一个值就行了 计算第二个参数 dwSize(EDX) 我的想法是让 eax 做运算,最后把 eax 的值赋给 edx。...计算第三个参数(ECX) 我们需要把 ecx 的值变为 00000040,在这个参数上我思考了好久,一直没有找到解决方法,本来我是这么打算的 xor eax,eax add eax,8 add eax,
Int 0x80的输入输出参数说明: 输入参数:eax=功能号(比如2为fork系统调用) 用功能对应sys_call_table[]的下标,比如sys_call_table[2]表示fork系统调用函数...fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, 返回值:EAX=sys_fork函数的返回值...为什么不能保存到用户态堆栈,如果保存了用户态堆栈,那么,这些栈内存区域,用户程序就可以必改定,那么,程序就很容易被攻击了,直接修改CS:EIP对应的栈内存,那么,你懂的^_^。...//系统调用函数的返回值入栈 关于进程状态的变化,参考书上的说明,这部分,理解的还不够,后续再分析???...所以,当从系统调用相关功能号对应函数返回时,需要检查当前进程是否还在就绪态,或时间片是否用完,并确认是否需要重新执行调度程序。
,紧跟在popad后的第一个JMP指令可跳转到OEP 实践: 1:查壳 2:OD打开 3:F8 //对于寄存器,指令执行后发生改变的寄存器会用红色显示,此处ESP和EIP的值发生改变...,因为执行pushad指令,将8个通用寄存器(EAX-EDI)的值保存至栈,栈中的值增加了,所以ESP的值发生变化,而EIP的值表示下一个要执行指令的地址,也发生变化 (执行PUSHAD的原因是使栈平衡...,这段代码的最后还有popad,两者执行后可以把ESP的值回到原值,这里不明白为什么使栈帧平衡要执行push和pop,如果没有这两步只执行movebp,esp,不是还有基准值,搞不懂push和pop的意义...ESP为000DFF54时,下一个命令是popad (popad指令把pushad存储在栈中的值再次恢复到各个寄存器,我理解为8次pop命令) 5:F9运行 //猜测未执行popad时,ESP...//发现OEP处寄存器的值除了EAX和EIP,其他的的值和pushad的值一样 EAX中值不一样的原因是,EAX中保存函数的返回值,保存的是OEP的地址 7:脱壳 总结: 1:
3、函数调用时形参是如何传递的,传递和调用的顺序又是怎样的? 4、为什么说形参是实参的一份临时拷贝,改变形参的值不会影响实参? 5、函数的返回值是如何带回去的?...相关汇编命令: mov:数据转移指令 push:数据入栈,同时esp栈顶寄存器也要发生改变 pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变 sub:减法命令 add:加法命令 call:...程序是在函数调用返回之后,在eax中去读取返回值的。...中 mov eax,dword ptr [ebp-8] 将ebp-8地址处的值放在eax中,其实就是 把z的值存储到eax寄存器中,这里是想通过eax寄存器带回计算的结果,...传参的顺序是从右到左,调用的顺序是从左到右。 5.4 为什么说形参是实参的一份临时拷贝,改变形参的值不会影响实参?
IAT表中无法找到,InlineHook算是对IATHOOK一个升级版吧 大体思路 用JMP改变函数入口,JMP到我们自己的函数,然后又JMP回去执行刚刚的没执行完的函数。...过程无论怎么变,一定要让堆栈平衡和保留原来的寄存器,这是Hook是否成功的关键....,后面我们要还原现场.这里我先创建了一个结构体用于接收寄存器的值,等会方便打印 typedef struct _regeist { DWORD EAX; DWORD EBX; DWORD ECX; DWORD...这里我找到一篇文章说明为什么有这种机制: https://blog.csdn.net/x_iya/article/details/13161937 测试结果 ?...我调用了两次函数,但只有一次输出说明卸载也成功了 完整代码 // InlineHook.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
但不能用于直接从内存复制到内存 push:数据入栈,同时esp栈顶寄存器也要发生改变 pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变 sub:用于两个操作数相减,相减的结果保存到第一个操作数中...当然我们还可以通过内存窗口看一下它是否真的压进去了: 因为现在esp指向的空间里前4个字节放到就是ebp的值 没问题。...esp里面的值发生了变化,并且我们上面push的eax上面好像又多push进去了一个值 而且我们会发现新push进去的这个值就是前面call 00EA10B4这条指令的下一条指令的地址。...是最终的结果z。 所以它又把Z的值放到了eax寄存器里面。 那大家思考一下,为什么不直接返回z呢?为什么要要把结果放到寄存器eax里面呢?...程序是在函数调用返回之后,在eax中去读取返回值的。 那再往下,是printf函数的调用,接着就是main函数栈帧的销毁,那它们和Add函数的调用以及栈帧的销毁是差不多的,我就不过多赘述了。
; 我们可以看到,这几句已经改变了ebx和edx的值,但是因为他是事先“打印”成文件再交给GAS进行汇编的,所以GAS不会知道已经这些寄存器的内容已经发生改变,仍然会假设寄存器的内容是合法的。...然后clobbers部分告诉GCC寄存器ecx和edi的内容可能已经被改变了。...*/ ); 这个代码实现的功能就是将a的值赋值给b,注意对应的输入输出部分是怎么写的。...然后是输出部分,输出部分是必须有=的,=r代表目标操作数可以使用任何一个通用寄存器,并且变量b存放在这个寄存器中(或者这么说,这个寄存器与变量b相关联,先将操作数的值读入寄存器,用这个寄存器执行相应指令...最后clobber部分表示汇编代码会改变eax寄存器的内容,这样gcc在调用内联汇编的时候就不会直接假设寄存器eax中内容合法并直接使用。执行完这段代码之后变量b的值就会被改写。
翻译: 表示一个变量也许会被后台程序改变,关键字 volatile 是与 const 绝对对立的。...我们知道 volatile 和 const 一样为类型修饰符,不改变变量类型。 寄存器地址为什么要加 volatile 修饰呢? 是因为,这些寄存器里面的值是随时变化的。...3、多线程应用中被几个任务共享的变量 当两个线程都要用到某一个变量且该变量的值会被改变时,应该用 volatile 声明,该关键字的作用是防止优化编译器把变量从内存装入CPU寄存器中。...,寄存器中bStop的值永远不会变成FALSE,加上volatile,程序在执行时,每次均从内存中读出bStop的值,就不会死循环了。...如 果没有 volatile 关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。
局部变量是如何创建的? 为什么局部变量不初始化其内容是随机的? 有些时候屏幕上输出的"烫烫烫"是怎么来的? 函数调用时参数时如何传递的?传参的顺序是怎样的? 函数的形参和实参的关系是什么?...---- 2、相关寄存器 eax:通用寄存器,保留临时数据,常用于返回值。 ebx:通用寄存器,保留临时数据。 ebp:栈底寄存器,用来记录栈底的地址。 esp:栈顶寄存器,用来记录栈顶的地址。...,本次函数的返回值是由eax寄存器带回来的。...程序是在函数调用返回之后,在eax中去读取返回值的。 ---- 7、对开篇问题的解答 当我们完整的了解了函数栈帧创建和销毁的过程后,我们就可以回答开篇提到的问题了: 局部变量是如何创建的?...函数的返回值通过eax寄存器带回。 函数是怎样在栈区上开辟和释放空间的?
一、寄存器:eax,ebx,ecx,edx,ebp,esp.而本文中重点提到的是esp和ebp! ebp和esp这2个寄存器中存放的是地址,这两个地址是用来维护函数栈帧的。...此时此刻,esp也要跟着变化,变化成了ebp的值: 变化前: 变化后: 接下来,便是move: ,意思是把esp的值给ebp,这意味着,ebp不再指向下面那个位置,而是指向esp现在所指的位置...其实很简单,看下面的指令:把ebp-8的值放到eax里面去,eax可是个寄存器啊,因此是不会因为程序退出而销毁的! ...紧接着,把eax的值放到ebp-20h中去,也就是c的地址 最后,打印,然后结束程序,销毁main函数的栈帧。 因此: ①局部变量是如何创建的? 给函数创建栈帧,再在空间里面分配变量的空间。...也就是说,是通过寄存器带回来的! PS:本人对函数栈帧的创建和销毁的拙见,请有大佬看到的其中不妥的问题时候,可以纠正我的问题。谢谢!
栈是一种简单的数据结构,之前学函数的时候我们一直在使用它,却没有意识到!...在计算机体系结构里,寄存器存储在已知时间点所作计算的中间结果,通过快速地访问数据来加速计算机程序的执行。...–百科 Name Function eax “累加器”, 用来存放函数的返回值 ebx "基地址"寄存器,可作为储存器指针来使用, 在内存寻址时存放基地址 ecx 计数器, 在循环和指针操作时,要用它来控制循环次数...为什么要将call指令的下一条指令的地址存起来呢??...,从而让程序可以继续执行。
2、认识相关寄存器和汇编指令 相关寄存器 eax:通用寄存器,保留临时数据,常用于返回值 ebx:通用寄存器,保留临时数据 ebp:栈底寄存器 esp:栈顶寄存器 eip:指令寄存器,保存当前指令的下一条指令的地址...相关汇编命令 mov:数据转移指令 push:数据入栈,同时esp栈顶寄存器也要发生改变 pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变 sub:减法命令 add:加法命令 call:函数调用...; for(; ecx = 0; --ecx,edi+=4) { *(int*)edi = eax; } 之所以上面的程序输出“烫”这么一个奇怪的字,是因为main函数调用时,在栈区开辟的空间的其中每一个字节都被初始化为...8] //将ebp-8地址处的值放在eax中 //其实就是把z的值存储到eax寄存器中,这里是想通过eax寄存器带回计算的结果,做函数的返回值。...答:形参是在栈帧空间中创建的独立空间,与实参相比值相同、空间相互独立,所以形参改变实参不会发生变化,因此说形参是实参的一份临时拷贝。 5、函数的返回值是如何带回的?
领取专属 10元无门槛券
手把手带您无忧上云