当前位置:   article > 正文

逆向(二):CALL_主线程调用call

主线程调用call

一、概念

具体的描述大家可以在网上找,在这里我就不再罗嗦了,大致意思为:通过调用程序自身的一些函数达到某种目的。

二、背景

虽然前面的HOOK已经可以实现一些特殊功能,但是对于一个线上的软件,只在本地做了修改是没有用的,因为服务器的数据并没有改掉,因此出现了CALL。

三、实现

仍以前面的Game为例进行CALL的说明,如下“弄死我自己”。
在这里插入图片描述

1、CALL代码构建
根据已有的逆向分析结果,该游戏中角色类中有一个成员方法——被攻击的函数beAct,其有两个int类型参数,分别为:伤害damage和攻击者在数组中的下标index。
首先还是需要在Game中分配一块内存空间写入CALL代码,如下:

// 还是瞎写的哈 。
#define PTR_THIS 0xaaaaaaaa
#define ACT_CALL 0xbbbbbbbb

char call_data[]
{
	0x51,                        // push ecx 因为后面使用了两个寄存器,要先将原来的值保存起来
	0x50,                        // push eax
	0x6A,0x02,                   // push 攻击者在数组中的索引 
	0x68,0x00,0x00,0x00,0x00,    // push 伤害,4字节,后面用指针打进来
	0xB9,0x00,0x00,0x00,0x00,    // mov ecx, 被攻击者的指针,即保存this指针 
	0xB8,0x00,0x00,0x00,0x00,    // mov eax, 被攻击函数的地址,使用寄存器是为了不计算
	0xFF,0xD0,                   // call eax 调用被攻击函数 
	0x58,                        // pop eax 恢复这两个寄存器的值 
	0x59,                        // pop ecx
	0xC3                         // return 函数要返回,否则崩溃 
};
int* _damage = (int*)(call_data + 5);
_damage[0] = 99999;

int* _beActer = (int*)(call_data + 10);
_beActer[0] = PTR_THIS;

int* _actCall = (int*)(call_data + 15);
_actCall[0] = ACT_CALL;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

关于call_data的说明:

  1. 开始的两次压栈,是因为后面需要用到这两个寄存器,所以需要先将其值保存起来,而后对应结尾的两次出栈。其中ecx保存被攻击者的指针是根据这是一个类确定的,因为ecx大多数都是保存this;而使用eax保存被攻击函数即beAct的地址是因为可以省去跳转的计算
  2. 结尾的0xC3,是为了返回用的,首先函数都有返回(虽然我们有时可以不写),其次这是分配出的一块内存空间,我们只是在这里写下了功能代码,当这些代码执行完之后,如果没有返回,CPU则会继续执行后面地址的其他指令,而后面是什么是不确定的!!!

2、如何调用CALL代码
虽然代码写完了,但是怎么调用,即怎么让CPU执行到这里?
我们都知道,进程是没有执行权限的而线程是有的,所以当进程创建时都会有一个主线程进行CPU的执行,进程为线程提供了一些环境以及部分的管理工作,所以问题就变成了获得线程执行权限。
方法有两个:1)劫持线程;2)创建远程线程。
本例以创建远程线程说明,因为劫持线程有一部分是HOOK。
调用API,如下:

DWORD Tid;
CreateRemoteThread(
	hGameProcess,                      // 目标进程句柄 
	NULL,                              // 为NULL表示获得默认的安全描述符,并且不能继承句柄 
	0,                                 // 初始堆栈大小 为0表示使用默认大小 
	(LPTHREAD_START_ROUTINE)call_kill, // 线程执行的起始地址 (函数指针)
	0,                                 // 线程函数的参数,为0表示没有参数 
	0,                                 // 创建线程后 立即执行 
	&Tid                               // 返回线程id 
	);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

其中call_kill是你创建的线程从哪里开始执行,即CALL代码写在内存中的地址。

当在对话框内勾选“杀死我自己”时,即完成了自杀。

四、总结

虽然HOOK和CALL都简单实现了一下,但是这都是靠汇编完成的,毕竟汇编是给机器看的,所以能不能不写汇编?
1、内联汇编

unsigned index = 2;
unsigned damage = 99999;
unsigned beActer = PTR_THIS;
unsigned dCall = ACT_CALL;
__asm
{
	push index
	push damage
	mov ecx, beActer
	call dCall
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

虽然还不是纯C++代码,但最起码看起来舒服多了,简明扼要的表达了我要做什么:传参、保存被攻击者的this指针、调用被攻击函数
2、纯C++代码
具体代码就不提供了,大致说下思路。

/*
	* 该函数为CreateRemoteThread函数中参数函数指针可以指向的
	* 根据已有的逆向分析,被攻击是一个类的成员函数,参数两个,均为int,分别为伤害和攻击者的序号
	* 理想情况下,希望通过player->beAct(int damage, int index)的形式完成此功能
	* 其中player为角色类的一个对象,此处代表人物角色 
	* 因为无法分析出完整的被攻击函数的实现内容,但是又已经知道了该函数的返回类型和参数,所以采用类的成员函数的函数指针来做 
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

剩下的大家自由发挥~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/486983
推荐阅读
相关标签
  

闽ICP备14008679号