郁金香外挂技术-郁金香灬老师

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

郁金香终身VIP管理员QQ150330575项目合作(有实力的+)视频教程+每月更新+QQ群
飞郁视频分享(每周更新)
查看: 1182|回复: 0

调call和偷功能时,VC中内联汇编容易产生的错误

[复制链接]
发表于 2019-6-19 15:32:41 | 显示全部楼层 |阅读模式
      最近,有不少刚学习内联汇编的网友和同学跟我聊,他写的内联汇编代码总是出现一些莫名其妙的错误,看上去明明是对的,却怎么也执行不成功。                                      甚至有的是,代码注入器都可以测试成功的汇编代码,复制到VC里不行了!感到很困惑。  
      那么,今天我们就一起来探讨一下这个问题,帮助刚学习内联汇编的同学和刚逆向入门的同学少走些弯路,少遇一些坑。
      
1.png


    我们先来看下什么是内联汇编?
内联汇编,指在C语言中插入汇编语言。
       内联汇编可以帮我们做什么?
1.可以帮我们在C语言中插入汇编代码。
2.可以帮我们调用目标程序的子程序(CALL)。
3.可以协助我们偷功能。
2和3  是可以做一些羞羞的事的,功能很强大
2.png


我们先来看一个简单的例子

3.png
下面的反汇编窗口是一个小游戏的吃药函数
push的第一个参数是 push 0
push的第二个参数是 push edx  
edx 是表示的药品位置(当然正常情况  我们不会选择这样参数的函数调用,位置参数一定是没有ID 参数调用方便的,这里只是随便举一个简单例子)
call 004FACD0 只是为了取一个返回值eax
然后把返回值赋值给  参数ECX
即mov  ecx,eax

最后调用函数  call00491C50

4.png

函数我们分析清楚了,就可以写代码了
首先先在代码注入器中编写代码
代码注入器中测试成功的代码(药品我们选择第一个位置的 ,edx 为0 )

我们看到除了变化的参数我们需要给其赋值以外,其他的代码就照抄的

5.png

然后我们到VC中进行内联汇编的编写

6.png

这里需要注意的只有两点
第一点,从反汇编窗口复制出来的数值都是16进制的,到VC里要加上个0x
例如  004F1CD0  写成  0x004F1CD0
第二点,call  立即数  语法是不合法的   需要用寄存器转一下
call0x00491C50   写成  mov  eax,0x00491C50   call eax
上面的例子可以看出内联汇编写法很容易

__asm{},把自己想插入的汇编代码直接按照汇编的语法编写即可。

7.png


感觉完了?不,才开始=。=
以上只是最简单的情况,在我们编写的过程中可能存在很多错误,主要表现为三种错误。
第一种错误,编译错误
这种错误编译器会提示我们,这种错误没什么难度,如下

8.png

不能直接call 立即数

9.png

标点符号要英文的

10.png

立即数不能作为左值
根据提示修改即可。
第二种,运行错误,当然编译器是不会管我们的,所以我们就要额外小心的使用内联汇编。
我们拿个例子看下

例如代码注入器测试成功的代码

11.png

我们按照规则修改成内联汇编代码如下
也编译通过了

12.png

但是这段内联汇编代码测试了好多次
调用一定是会崩溃程序的(代码注入器的完全没有问题)
为什么?

13.png

那我们可以选择逆向我们自己的代码来看看情况,由于我写的是MFC dll
需要注入到游戏中运行的,所以我们附加上这个小游戏 ,然后去看我们的代码

首先我们在自己的内联汇编中加一些特征  ,方便我们直接定位跳转过去。

14.png


这样的特征,正常代码 是打死也不会有的。
点开E

15.png

找到我们的模块 我们的DLL.dll
16.png

入口地址 37542D16

CTRL+G 跳过去

17.png

18.png

回车来到模块领空

19.png


CTRL + S 搜索我们的特征码

20.png


找到了我们的内联汇编代码

21.png

我们来对比一下代码

22.png

23.png

是不是发现 我们代码 mov  ecx,[0x00D0DF1C]  的括号没有了
有的人会说,  这是你没有加  dword ptr

那么我们加一下试试

24.png

发现代码依然是这样的

25.png

那么怎么办?
我们怎么写才能不出错误

代码写成这样就可以了

26.png

这是根本看不出来的可能的错误,一个是靠我们已经有的经验解决
另外一个就是,我们出现问题 ,用上面的方法到游戏里定位问题,解决问题,永远是最好的方法。

第三种,可以预知的运行错误

27.png

28.png

看上去没有什么错误,但是实际上这样运行是百分百会崩溃的。
原因很简单,汇编代码不合法!
有的同学会说哪里不合法啊?
我们看int a[3]= {7,键码,1}; 一个数组,在逆向的本质里,其实就是3个局部变量而已
[ebp-4],[ebp-8],[ebp-C]
而 a是这个数组的首地址  即ebp-C
那么我们看  下面的内联汇编中
push a 是否合法
push  a  等价于  push  ebp - C
那么当然是不合法的!
因为不合法 ,编译器 不会编译出现不合法的代码的
他强制将代码编程成  push [ebp-c]  这样参数含义完全变化,程序执行过程自然出现错误,导致崩溃也是必然的了。
想要解决
所以我们要改成以下代码
正确的方法一
我们 lea ebx,a[0]
相当于  lea ebx,[ebp-C]
然后再 push ebx
这样就合法了

如下图

29.png

正确的方法二
把指针转换成  用局部变量存放 然后再PUSH



31.png

总之,使用内联汇编,一定要对其机制比较了解
否则稍不小心,会在上面浪费很多调试时间
32.png


   处于好奇心,我也百度了一下,看看是不是也有很多人出现过类似的问题,果然找到了几个,我已经对其进行了一一解答。
   简单截图2个具有代表性的问题 我们一起看一眼

1.
33.png

上面的例子,就是我们第二种错误的情况
代码需要写成
push 0
moveax,0x1E22DD8
moveax,[eax]
push eax
push 0
这样就可以了
2.

34.png


上面的例子,就是我们第三种错误的情况
编译器认为代码不合法,强行编译的错误
并不是内联汇编不把字符串名当指针看待,而是你的汇编代码不合法,
编译器为了能够编译,编译结果自然和你想的不是一样的了。
a 是字符串名,看上去 mov  ebx,a   就可以了。
但是  真要是编程出来了,你还认识这样的汇编代码吗? mov  ebx, ebp-xx ????
35.png


他真要编译出来是不是你认都不敢认,没见过这样的代码啊!
所以他只能编译成合法的代码吧。 那就是mov  ebx,[ebp-xx], 也就是你所谓的,把指针硬当成变量看,编译器心里苦啊,是您逼迫我这样干的!
偷功能
偷功能其实和写call  没有什么本质的区别了,只是需要抄下来的代码更多一些
更确切的说是复制粘贴出来修改的代码更多一些。

36.png


复制出来的汇编代码需要进行初步处理才能写到内联汇编中
例如常数全部要加上0x
例如,call xxxxx  都要用寄存器转一下
例如 mov  eax,[0x12345678] 这种代码也要转一下
等等
还有一个最重要的,就是跳转要修改
例如 jnz  12345678 他是要跳转到目的代码地址执行的,我们偷出来的代码已经不是原来的地址了
所以要通过标签修改跳转的地址。
跳转的写法
我们随便截取一段代码,来说明跳转怎么修改

37.png

内联汇编中的写法
__asm
{
     mov esi,[eax]
     cmp  esi,eax
    Je Label1  //         不能再写  je 0x66C66F
Label2:   //                 跳转过来的标签
    mov edi,esi
    mov esi,[esi]
    push 0
    lea ecx, [edi+8]
    mov eax,0x0066CC60
   call  eax
   push 1
   push edi
   mov ecx,ebp
   mov eax,0x0066cc20
   call eax
   cmp esi,[ebp]
   Jnz  Label2     //         不能再写  je 0x66C652
Label1: //                 跳转过来的标签
   mov eax,[ebp]
}

我们查看自己的代码看是否正确

38.png

发现是正确的
当然偷功能的时候
我们尽量偷完整的函数代码,而不是中间一段
并且要传递正确的参数,才能执行成功。

绝对地址跳转

39.png

同样是不可以直接 jmp   xxxx

40.png
41.png


这样就可以了
如果是JMP 这样写就可以了
因为我们知道 jmp 的操作数可以是寄存器
而JNZEAX  是不合法的
jnz 等条件跳转怎么绝对地址跳转呢

42.png

43.png

不可以
我们增加代码 继续尝试

44.png

45.png

发现无论你后面立即数写多少 都是没用的
他只是跳到下一条
因为   立即数  都被编译成了  00000000
目前已经知道解决方案有3个
一个是用标签
一个是自己判断数据,进行跳转

最后一个方法就是 自己计算跳转值  在代码里进行修改了,这种方式推荐裸函数,容易计算偏移

46.png

现在确实是不对的

那么我们  自己改写即可

47.png

0x371C5960 到 0x371C5984 是0x24字节  加上  0F84  的两字节
偏移是 0x26字节
也就是说 我们要修改的地址 是从函数头部+0x26的位置
我们修改成的值 是  跳转目标  -  本条代码地址  -5
既下面代码
DWORD temp =0x12345678 - ((DWORD)&aaa+0x24) -5 ;
然后把值写入  函数头部+0x26的位置
*(DWORD*)((DWORD)&aaa+0x26)= temp;


48.png

调用以后的效果

49.png

相当于串改了代码,不过是自己的代码
值得注意的是,如果函数有Jmp跳转需要再加入计算

先讲到这里,欢迎补充和探讨!

6173O3RZ9V6SFH`V[8TO.jpg

飞郁网络培训:www.feiyuol.com
微信公众号:任鸟飞逆向

腾讯课堂:feiyuol.ke.qq.com         

30.png
20.png
郁金香外挂教程,学习中...
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

限时限量优惠

QQ|小黑屋|手机版|郁金香外挂技术-郁金香灬老师 ( 苏ICP备10059359号 )

GMT+8, 2019-12-13 07:33 , Processed in 0.065863 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表