32位汇编第四讲,⼲货分享,汇编注⼊的实现,以及快速定位调⽤
API的数量(OD查看)
32位汇编第四讲,⼲货分享,汇编注⼊的实现,以及快速定位调⽤API的数量(OD查看)
昨天,⼤家可能都看了代码了,不知道昨天有没有在汇编代码的基础上,实现注⼊计算器.
如果没有,今天则会讲解,不过建议把昨天代码熟悉⼀遍(课程是紧跟着来的,请不要拉下任何⼀天,因为今天的知识,
可能就和昨天的知识挂钩,昨天的知识,和前天的挂钩.....,当然你如你懂汇编,不是新⼿,那么则可以直接往下看)
⼀⼂远程线程注⼊,和汇编远程注⼊的区别
昨天的代码,⼤家可能看了(没看也没有关系,就是远程线程注⼊的代码,开发⾓度,和汇编代码注⼊,底层⾓度的两份代码)
这⾥说下,他们的区别
⾸先我们知道,任何注⼊⽅式都有它们使⽤的特定场合
1.远程线程注⼊
这个只针对软件的保护防范低使⽤的,病毒很少⽤这个,为什么
我们知道,远程线程注⼊,它会创建远程线程,进⽽加载我们的DLL,⽽对有保护的程序来说,它可能不能防范你使⽤CreateRemoteThread函数,但是可以针对你的dll,⽐如遍历dll个数
发现多了⼀个,程序就退出.等等.
2.汇编的远程注⼊
汇编的远程注⼊,这个就有点狠了,为什么,因为你写的不是⼀个dll,⽽是⼀断汇编代码,写到对⾯的内存中,让他去执⾏,这样除⾮对⾯软件,试试的检测内存状态,否则不容易检测出⾃⼰程序的异常
当然汇编的远程注⼊,还是会开辟内存,但是我们知道,注⼊⽅法很多种,我们可以发挥想象,只重剑意不重剑招,我们可以这样想,你不是要申请内存吗,我们可以不申请内存,对⾯程序肯定会存再对齐的问题
,
⽐如为了保证对齐,对⾯程序肯定会⽤NOP指令填充,那么我们则可以利⽤这块内存,这样软件除⾮也检测NOP,和对齐,否则你注⼊进去对⾯也发现不了,再⽐如对⾯软件很厉害,检测很到位,厉害到
对齐也检测了,那么我们可以把对⾯栈的内存抬⾼,把我们的程序代码写进去,对⾯总不注意试试的检测栈吧,执⾏完我们的代码就出栈,对⾯不可能检测栈的进出吧.所以重在想像(废话有点多,可以省略不看直接看下边 :) )
3.汇编远程注⼊代码分析(0D分析)
昨天我们因为时间关系,没有具体分析昨天的代码,今天我们⽤OD(OlleyDbg)⼀步⼀步分析,
这个分析也能让我们快速的掌握调试技巧
①分析FindWindow,看下汇编代码执⾏了什么
⾸先贴出我们昨天的代码
invoke FindWindow,NULL,offset g_szWindowName ,第⼆个参数是计算器的字符串
mov @hWnd, eax
.
if eax == NULL
invoke ShowLastError
ret
.endif
上⾯代码的逻辑:
寻计算器,返回计算器的窗⼝句柄,如果成功,(返回值默认放eax中)
如果成功,继续往下执⾏,如果失败,调⽤ShowLastError显⽰错误信息
OD分析
这个是我们⼤体的FindWindow界⾯
我们查下窗⼝,看下是否到,到则窗⼝句柄放在eax当中
我们可以看出,已经到窗⼝了,并且窗⼝句柄已经在eax当中了,所以 eax == NULL 不成⽴,则跳转到下⼀条指令位置执⾏,⽽下⼀条指令位置,则开始调⽤GetWindowThreadProcessID了
②GetWindowThreadProcessID,获得进程的ID
⾸先还是对应着伪指令的汇编代码查看
invoke GetWindowThreadProcessId, @hWnd, addr @dwPID
代码很简单,我们知道,调⽤函数传参的时候,代码都是从右往左压栈的,所以第⼀个会 push dwPid,第⼆个会push hWnd
OD分析
因为⾛⼀步截次图太⿇烦,⽽且影响⼤家观看,索性直接标号,把每⼀步写出来,这样⼤家⾃⼰调试,不懂的时候来看我的每⼀步代表什么意思
⾸先我把每⼀步执⾏的代码都⽤标号圈起来了
1. lea eax,[local,3] 意思是我要拿第三个局部变量,也就是栈的第三个局部变量,⽽我们以前说过,局部变量都是 ebp -xxx来获取,⽽现在是32位的汇编了,所以每个寄存器是4个字节,所以第三个局部变量则是-12 ,⽽对应局部变量
则是 -c
这句代码真实的代码则被翻译成了
lea eax,dword ptr ss:[ebp - oxc]位置,我们就可以去栈中看下ebp -c的位置是什么了,注意这⾥因为我⾛到下边
所以已经获取到了进程PID的值,所以是810,默认的时候是0,那么是什么意思那,就是取得 ebp -c 的地址
2.取得ebp的地址(假设地址是18ff44)那么吧地址给eax,再把eax⼊栈,
3.把我们的第⼀个局部变量,也就是ebp - 4的值,(40D40,因为这⾥是中括号,所以对栈取内容得出的,⽽上⾯的是没有取内容,因为我们⽤的是lea 指令)
4.调⽤GetWindowThreadProcessId,这个时候,因为我们把第⼆部的eax⼊栈(eax是ebx-c的栈地址),所以获得的PID
值则会给对应栈地址的内容(什么意思: 就是你提供局部变量的地址,也就是我们先前ebp -c的地址,操作系统获得PID的值,则会根据你给的地址,把对应地址⾥⾯的内容修改了,所以相当于是 mov dword ptr[18ff44],810)
⾄此,我们可以总结下,这个GetWindowThreadProcessId,执⾏的过程
1.先获得局部变量的地址(ebp - c的地址,注意,不是值)
2.压栈
3.获得栈中第⼀个参数的值,(注意是栈地址⾥⾯的值,⽽不是栈地址)也就是上次获得的窗⼝的句柄
4.调⽤GetWindowThreadProcessId,把对应栈地址⾥⾯的值修改为我们的PID值(810),所以我们已经得到PID的值了
汇编代码:
invoke OpenProcess,PROCESS_ALL_ACCESS, FALSE, @dwPID
mov @hProcess, eax
.if eax == NULL
invoke ShowLastError
ret
.endif
⾸先,把PID压栈,然后把FALSE(汇编中是0)压栈,然后把权限压栈(权限就是常量)
最后打开进程,如果成功获得进程句柄,则返回值放在eax中,把eax给局部变量
然后判断局部变量是否==NULL,不想等继续⾛,相等就是打开失败,执⾏错误代码提⽰(ShowlastError)
OD分析
这个地⽅我也不⽤细讲了
1.⾸先,我们把进程的PID,也就是局部变量第三个(ebp - c⾥⾯的值)压栈
2.其次从右往左压⼊第⼆个参数,也就是FALSE
3.然后压⼊权限
4.调⽤OpenProcess
5.成功则eax保存的是进程的实例句柄
6.判断eax是否等于NULL,相等(获取失败)继续往下执⾏,调⽤Call injectas.0040118b
④VirtualAllocEx,远程申请内存
汇编代码
invoke VirtualAllocEx,@hProcess, NULL, 1000h, MEM_COMMIT, PAGE_EXECUTE_READWRITE
mov @lpBuff, eax
.if eax == NULL
invoke ShowLastError
ret
.endif
这个和上⾯⼀样,都是从右向左⼊栈,如果成功,返回在远程进程申请的内存的⾸地址,放在eax当中
失败则下⾯判断.
OD分析(注意,这种的上⾯都已经分析了很多遍了,API调⽤的传参,出栈,以及寄存器给局部变量赋值)
所以下⽅的API我会提供图⽚去看,但是不具体分析了,都是⼀样的,如果⼜兴趣的可以,⾃⼰练练⼿,⼿动分析,看下代码流程怎么执⾏.已经成功了,肯定会执⾏,现在介绍OD的第⼆种⽤法
当⼀个应⽤程序被打开的时候,我们可以选择附加的⽅式,将这个程序挂起
现在我们把计算机附加,看下这个地⽅是否申请了内存
重新打开OD,现在是两个OD
,选择我们的计算器程序
搜索我们⽤申请成功的内存⾸地址,看看是否申请成功
申请成功,然后我们继续下⼀条指令执⾏,写内存数据到这⾥⾯
⑤,利⽤WriteProcessMemory写内存数据到这⾥⾯来
注意,我们写的使我们的INJECT_CODE的代码的⼆进制,所以程序在调⽤远程线程的时候,
会把我们的⽽⼆进制当做代码运⾏
看下汇编代码:
invoke WriteProcessMemory,@hProcess,
@lpBuff,
INJECT_CODE,
start - INJECT_CODE,
NULL
传参,什么的不说了,这⾥需要注意⼀下要写⼊的内容是我们刚才申请的内存⾸地址
现在给的是lpBuff,也就是我们往哪⾥写,(往计算机器我们申请的哪块内存写,所以lpbuff就是计算器这块内存的⾸地址了)
写⼊的数据是 INJECT_CODE的代码的⼆进制
写⼊的⼤⼩是START - INJECT_CODE数据的⼤⼩
INJECT_CODE是在START标号的上⾯,我们看下
汇编代码,和OD分析
OD分析
可以看到,我的标号
1.表⽰我们要写⼊对⾯内存的起始地址(也就是我们⽤vir申请的)
2.我们要写⼊的缓冲区,也就是我要写⼊inject为开始,开始把这块内存写⼊
3.写⼊的⼤⼩就是我们计算出来的START- INJECT_CODE
4.实际写⼊的字节我们不关⼼,关于START - INJECT_CODE我们看下代码开始出就明⽩了
相当于00401017 - 00401000 = 17个字节,所以要写⼊17个字节
看下计算机程序中,有没有写⼊我们的⼆进制代码
正好17个字节,⽽且代码也写进去了
最后我们调⽤CreateReomteThread开始把INJECT_CODE当做代码去执⾏了,这⾥传参和上⾯⼀样
不在分析了
⾄此,分析到这⾥就完了,下⾯写代码就不分析了,开始真正的写汇编代码注⼊的程序了,因为汇编代码和上⾯⼤同⼩异都是调⽤API,⽽后API传参.保存返回值给局部变量,出栈等等都是⼀样的,所以下⽅开始真正写.如果感性区,想提升⾃⼰的调试能⼒,以及对OD的熟练程度,可以⾃⼰去分析⼀下
⼆⼂汇编注⼊代码的编写,以及应该注意的各种问题
⾸先,如果做过昨天作业的同学应该知道,会遇到对⾯代码和我⽅代码的的位置不⼀样
⽐如
我们INJECT_CODE的位置,和对⾯INJECT_CODE代码的位置
还有就是DLL加在的位置不同,也会影响API的调⽤
⽐如我们代码在INJECT_CODE⾥⾯调⽤⼀个MessageBox,他可以弹窗
但是要注意,在对⾯的那边调⽤这个就会出错,为什么
所以我们要注意⼏个问题
1.Call的时候问题
2.地址重定位问题
⾸先是1问题
①Call的时候的问题
我们在汇编代码中随便看⼀个Call 然后按下空格键,看下汇编是什么
我们分别在⾃⼰程序的INJECT_CODE 和对⾯程序的INJECT_CODE看下执⾏MessageBox会出现什么问题
这个是汇编代码
看下OD
我们可以看到都是调⽤0x401204,但是结果是正确的吗
我们⽤在反汇编窗⼝ CTRL + G 跳转到00401204 我们发现
第⼀个程序,也就是我们的注⼊程序,它调⽤MessageBox,是有的
⽽计算器的程序调⽤的时候,是没有的,不到这块内存,所以就出错了
字符串函数怎么获取为什么会出现这个问题,这个就是著名的重定位问题,以前我们DLL注⼊的时候,是系统帮我们重定位了
⽽现在我们要⾃⼰去重定位这个问题
⾸先我们知道,任何程序运⾏的时候,都会加在ntdll, ⽽kernel32.dll也会加载,user32.dll也会加载
⽽kernel32.dll并不是必须加载的,但是%99.999的程序都会加载这个dll ((*^▽^*))
user32.dll是和⽤户相关的,也会有%99的加载
那么就产⽣⼀个问题,看下图
我们注⼊程序调⽤MessageBox会从user32.dll中到MessAgebox的地址,并且调⽤
⽽B程序,显然DLL的⾸地址是2000的位置,⾸先不说我们能不能调⽤它
就我们刚才看Call的时候,他是直接call了⼀个常量 00401204,⽽显然,这块内存是不属于B进程的所以出错了
他是属于A进程的,
所以我们要重定位API地址
怎么定位
1.获得当前注⼊程序的User3
2.dll的加载的实例句柄
2.并且创建进程快照遍历计算机器进程模块User32.dll的实例句柄
然后看下图
⾸先注⼊程序得出1000h ,远程的程序得到的user32.dll的模块地址是2000h
3.获得MessageBox距离模块的偏移,注意,这个偏移获取出来,是两⽅都⼀样的,因为函数的位置都是⼀样的,只有
模块地址加载的位置不⼀样
看图
算出来的都是100, 所以我们就有了⼀个公式
函数⾸地址 - 模块⾸地址 = 得出了函数距离模块的实际偏移
然后远程模块 + 函数距离模块的实际偏移,得出远程进程的Messagebox的实际偏移
假设我们本地进程是1000h Messagebox的距离是1100
那么 1100 (函数⾸地址) - 模块⾸地址(1000) = 实际偏移(100)
然后远程模块地址(2000) + 实际偏移(100) = 实际函数地址
这个公式请熟练记住
看字不明⽩,看图:
先看公式,再看箭头指向
那么基于这个公式我们就开始写我们的汇编代码了
现在的函数地址重定义问题已经解决了,但是注意,只是函数地址的重定位
下⾯写完汇编代码,就明⽩,另⼀个函数调⽤地址⽆关性的重定位问题了,
也就是我们要解决的第⼆个问题,说的有点多,看代码,其实代码很简单
LOCAL @hLocalUser32Module:MODULE ;存放本地User32.dll的模块地址
LOCAL @hRemoteUser32Module:MODULE ;存放远程user32.dll的模块地址
;1.调⽤GetModule加载user32.dll获得user32.dll的模块地址
invoke GetModule,offset g_szUser32 ;g_szUser32看做字符串user32.dll,就是dll需要这个字符串,去寻user32.dll,如果想看完整⼯程
请下载每天资料查看
mov @hLocalUser32Module,eax ;返回值存放user32.dll模块地址,给局部变量 @hRemoteUser32Module,eax; 按理说这⾥应该遍历被注⼊进程的模块;获得user32.dll的地址,但是这⾥我的都是同系统,所以dll位置是⼀样的,如果你把这个注⼊程序给另外⼀个系统就要⾃⼰遍历了,遍历代码就不写了,和调⽤API
;⼀样,如果不会写,可以下⽅评论.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论