在学习逆向前我们需要掌握一些汇编的基础知识的
同时我们得知道可执行文件的原理
计算机生成可执行文件,我们大致可以简单的这么理解
1.asm源程序文件
2.asm源程序生成obj也就是目标文件
3.由目标文件链接生成可执行文件,Windows的可执行文件通常是EXE,Linux通常是ELF
而在实际的环境中,计算会选择丢弃部分不要重要,或者自己优化一些信息。
逆向就是需要对这些信息进行还原,同时可以进行破译,也就是游戏开外挂,软件正版却有盗版的存在
首先用查壳工具先看看
64位,ELF文件
查壳的目的:
1.看加了什么保护没
2.看看是多少位的程序,因为IDA有32和64的版本,必须与之分别对应
逆向基本步骤是使用IDA,对源程序进行反汇编,分析其中的代码
IDA(Interactive Disassembler)是一款强大的逆向工程工具,常用于分析和反汇编计算机程序。它支持各种平台和体系结构,并提供了丰富的功能和工具,可用于深入研究二进制代码的功能、结构和漏洞。
以下是IDA的一些主要特点和功能:
1.反汇编和分析:IDA能够将二进制文件转换为可读的汇编代码,使用户可以更好地理解程序的内部结构和执行逻辑。它提供了丰富的反汇编视图和分析工具,以帮助用户识别代码块、函数、指令和数据。
2.交互式界面:IDA提供了直观且易于使用的图形用户界面,支持用户与反汇编结果进行交互。用户可以浏览代码、跳转到函数或指令,查看和编辑数据以及设置断点等。
3.反编译器:IDA还提供了反编译功能,可以将汇编代码转换为高级语言表示,如C语言。这可以帮助用户更好地理解程序的功能和逻辑,尤其是对于无法获得源代码的情况。
4.插件和脚本支持:IDA支持各种插件和脚本,用户可以根据需要扩展和定制工具。这使得用户可以编写自己的脚本来自动化任务、添加新的功能或与其他工具集成。
总体而言,IDA是一款功能强大且灵活的逆向工程工具。它被广泛用于恶意软件分析、漏洞研究、软件安全评估和逆向工程等领域,并受到安全专家、软件工程师和研究人员的青睐。
同时IDA可以按F5,生成C/C++代码
以Test1为例子
打开IDA左边这一栏代表的是所用到的函数,当然我们知道C语言是从主函数开始的,所以一般我们先会去看看main函数的样子,当函数少的时候,我们可以直接看到,但是当函数多的时候我们就看不到了,此时我们用Ctr+f的方式可以在左边的篮筐进行搜索
由于这题比较简单,突破口就是main函数
这里需要我们有C语言的基础,仔细看好
每一个变量,每一个函数的逻辑关系
当然由于这道题说了考察异或那我们重点观察异或!!(这里其实已经在汇编、离散数学中学过)
异或(XOR)是一种逻辑运算符,常用于计算机科学和电子工程中。异或操作符通常用符号 “^” 表示。
异或操作的定义如下:
当两个操作数的位值不同时,异或结果为1。
当两个操作数的位值相同时,异或结果为0。
例如,对于两个二进制数1和0进行异或操作:
1 XOR 0 = 1
异或操作还具有以下一些重要性质:
1.结合律:(A XOR B) XOR C = A XOR (B XOR C)
2.交换律:A XOR B = B XOR A
3.自反性:A XOR A = 0
4.零元素:A XOR 0 = A
异或操作在计算机科学中广泛应用,包括数据加密、校验和计算、错误检测和纠错编码等领域。在编程中,异或操作也常用于快速交换变量值、判断奇偶性和重复元素的消除等。
根据上面我们现在知道,把密码重复异或两次就会出现成本身,那么这道题的思路:
1,找到匹配的数据
2.将匹配的数据进行二次异或
3.最后得到原来的密码,也就是我们所需要的信息
int __cdecl main(int argc, const char **argv, const char **envp)
{
size_t v3; // rbx
char s[8]; // [rsp+0h] [rbp-40h] BYREF
__int64 v6; // [rsp+8h] [rbp-38h]
__int64 v7; // [rsp+10h] [rbp-30h]
__int64 v8; // [rsp+18h] [rbp-28h]
char v9; // [rsp+20h] [rbp-20h]
int i; // [rsp+2Ch] [rbp-14h]
*(_QWORD *)s = 0LL;
v6 = 0LL;
v7 = 0LL;
v8 = 0LL;
v9 = 0;
puts("Welcome to RE world,Can you solve the problem?");
printf("Now you should input your flag and i'll tell you if it is right:");
__isoc99_scanf("%s", s);
for ( i = 0; ; ++i )
{
v3 = i;
if ( v3 >= strlen(s) )
break;
s[i] ^= i; **重点!!!
}
if ( (unsigned int)compare(s) )
puts("Well done! You find the secret!");**根据这里的提示我们看到如果(unsigned int)compare(s)
成立==1那就说梦成功了,那这里我们在IDA里面点进这个函数看看
else
puts("The flag is wrong! Maybe something run before main");
return 0;
__int64 __fastcall compare(const char *a1)
{
int i; // [rsp+1Ch] [rbp-4h]
if ( strlen(a1) != 32 )
{
puts("The length of flag is Wrong!!");
exit(0);
}
for ( i = 0; i <= 31; ++i )
{
if ( final[i] != a1[i] )**这里我们看到我们输入的字符串被传输进入了a1[]里面,然后与fianl[]里面的数做了
一个对比,那其实就是final[]就是加密后的密码,点击进入查看数据
return 0LL;
}
return 1LL;
}
学逆向我们还需要懂得一些文件结构的基础,这里我之前有讲过可以去看看下面这篇我写的博客
https://blog.csdn.net/m0_72827793/article/details/130231662
里面讲了PE文件结构,当然这道题是ELF文件结构,但他们都是类似的,都在COFF的基础上
可以在我博客上的汇编框里面找找
这些数据就是我们需要破译的密码
这里我们需要提取出来选中这些数据
shift+e
我们选择十六进制转换
我们把数据提取出来(0X)表示十六进制
0x66, 0x6D, 0x63, 0x64, 0x7F, 0x56, 0x69, 0x6A, 0x6D, 0x7D,
0x62, 0x62, 0x62, 0x6A, 0x51, 0x7D, 0x65, 0x7F, 0x4D, 0x71,
0x71, 0x73, 0x79, 0x65, 0x7D, 0x46, 0x77, 0x7A, 0x75, 0x73,
0x21, 0x62
这里我们可以C语言,也可以用python等一些语言写一个破译的脚本
这里是我写的
运行即可
学了上面这些,我们再加深一下理解,同时做一个提升
看一下同类型的test2这道题
同样的方式先找到main函数
解析这段
if ( Size != 38 )**这里判断了输入的数必须是38个
goto LABEL_22;
v5 = 0i64;
v3 = &Buf1;
do
{
v6 = &Buf1**给数赋值
v7 = &Buf1;
if ( (unsigned __int64)qword_7FF7B8B96C68 >= 0x10 )
v6 = (void **)Buf1;
if ( (unsigned __int64)qword_7FF7B8B96C68 >= 0x10 )
v7 = (void **)Buf1;
*((_BYTE *)v7 + v5) ^= *((_BYTE *)v6 + v5 + 1);**给数组str[i]^=str[i+1],下面的依次类推分析
v8 = &Buf1;
v9 = &Buf1;
if ( (unsigned __int64)qword_7FF7B8B96C68 >= 0x10 )
v8 = (void **)Buf1;
if ( (unsigned __int64)qword_7FF7B8B96C68 >= 0x10 )
v9 = (void **)Buf1;
*((_BYTE *)v9 + v5 + 1) ^= *((_BYTE *)v8 + v5 + 2);
v10 = &Buf1;
v11 = &Buf1;
if ( (unsigned __int64)qword_7FF7B8B96C68 >= 0x10 )
v10 = (void **)Buf1;
if ( (unsigned __int64)qword_7FF7B8B96C68 >= 0x10 )
v11 = (void **)Buf1;
*((_BYTE *)v11 + v5 + 2) ^= *((_BYTE *)v10 + v5 + 3);
++v5;
v4 = Size;
}
while ( v5 < Size - 3 );
v12 = &Buf2;**先看明白下面
Size != qword_7FF7B8B96C40 || (v13 = memcmp(v3, v12, Size), v14 = "Right!", v13)
这个判断,再看这个!
**此时我们我们便可以知道Buf2就是判断的值
if ( (unsigned __int64)qword_7FF7B8B96C48 >= 0x10 )
v12 = (void **)Buf2;
if ( (unsigned __int64)qword_7FF7B8B96C68 >= 0x10 )
v3 = (void **)Buf1;
if ( Size != qword_7FF7B8B96C40 || (v13 = memcmp(v3, v12, Size), v14 = "Right!", v13) )
LABEL_22:
v14 = "Wrong!";
sub_7FF7B8B62410(v3, v14, v4);
return 0;
可以当我们点开buf2发现,这里面啥也没有
**所以我们需要动态调试!!**数据节(data section)是程序的一部分,它存储了静态和全局变量的初始化值。在程序执行过程中,这些变量的值可能会被修改或者被其他操作所影响。因此,通过动态调试,在程序运行时可以实时查看这些变量的当前值,而不仅仅是它们的初始化值。
由于动态调试可以在程序运行时观察和修改内存中的数据,因此可能需要使用动态调试来确认 Buf2 的具体值,以便确定判断条件的结果
其实IDA通常不用于动态调试,IDA一般当作地图来使用,我们通常会选用OD或者X64dgb进行动态调试
这里我们还是讲解一些IDA动态调试
设立断点
选择start process
或者直接按F9即可
输入38个字符
在看到IDA
F7步入,F8不过
不过这里当我们执行过
v12 = &Buf2;这条语句时,我们会看到这个
点击小坐标我们进去看看
会出现这样的画面,同时我们再点击进入下面箭头所指的部分
跳转到这样的画面
如果你不清楚,数据是哪里开始的你可以回到刚才上一页的地方
看到这样的画面
至于结束会出现在这里,也就是0的前面
我们再次提取数据,用上一道题讲过的方法
0x0A, 0x0B, 0x7D, 0x2F, 0x7F, 0x67, 0x65, 0x30, 0x63, 0x60,
0x37, 0x3F, 0x3C, 0x3F, 0x33, 0x3A, 0x3C, 0x3B, 0x35, 0x3C,
0x3E, 0x6C, 0x64, 0x31, 0x64, 0x6C, 0x3B, 0x68, 0x61, 0x62,
0x65, 0x36, 0x33, 0x60, 0x62, 0x36, 0x1C, 0x7D,
这里给出了两个语言写的代码,自行研究一下
#include
#include
int main()
{
int i=0;
int str[38]={ 0x0A, 0x0B, 0x7D, 0x2F, 0x7F, 0x67, 0x65, 0x30, 0x63, 0x60,
0x37, 0x3F, 0x3C, 0x3F, 0x33, 0x3A, 0x3C, 0x3B, 0x35, 0x3C,
0x3E, 0x6C, 0x64, 0x31, 0x64, 0x6C, 0x3B, 0x68, 0x61, 0x62,
0x65, 0x36, 0x33, 0x60, 0x62, 0x36, 0x1C, 0x7D};
int str1[38]={0};
int str2[38]={0};
for(i=0;i<38;i++)
{
str1[i]=str[37-i];
}
for(i=3;i<38;i++)
{
str1[i - 2] ^= str1[i - 3];
str1[i - 1] ^= str1[i - 2];
str1[i] ^= str1[i - 1];
}
for(i=0;i<38;i++)
{
str2[i]=str1[37-i];
printf("%c",str2[i]);
}
return 0;
}
Python注意缩进
k= [
0x0A, 0x0B, 0x7D, 0x2F, 0x7F, 0x67, 0x65, 0x30, 0x63, 0x60,
0x37, 0x3F, 0x3C, 0x3F, 0x33, 0x3A, 0x3C, 0x3B, 0x35, 0x3C,
0x3E, 0x6C, 0x64, 0x31, 0x64, 0x6C, 0x3B, 0x68, 0x61, 0x62,
0x65, 0x36, 0x33, 0x60, 0x62, 0x36, 0x1C, 0x7D
]
s = k[::-1]
for i in range(3, len(s)):
s[i - 2] ^= s[i - 3]
s[i - 1] ^= s[i - 2]
s[i] ^= s[i - 1]
s=s[::-1]
for i in range(len(s)):
print(chr(s[i]), end='')