0x0 题目涉及知识点
- 简单脱壳
- 指针运算
- 位移量
- 字符串查询
0x1 查壳脱壳
使用 UPX 工具脱壳
0x2 反汇编分析
初步了解程序执行流程,sub_401000(&v6)
为加密过程,&v4中存放了flag。
char v4; // [esp+4h] [ebp-804h]
char v5; // [esp+5h] [ebp-803h]
char v6; // [esp+404h] [ebp-404h]
char Dst; // [esp+405h] [ebp-403h]
v6 = 0;
memset(&Dst, 0, 0x3FFu);
v4 = 0;
memset(&v5, 0, 0x3FFu);
这两句有一些特殊,是以Dst和V5的地址为数组首地址,创建0x3FF大小缓冲区用于存放数据。
可视化分析流程,得到 you have got it
逆向就完成。
中间部分是我们需要逆向分析的算法,算法中有一个向上的跳转作为循环
scanf("%s", &v6);
sub_401000(&v6);
输入字符串,并将地址传入 sub_401000()
unsigned int __cdecl sub_401000(const char *a1)
{
_BYTE *v1; // ecx
unsigned int v2; // edi
unsigned int result; // eax
int v4; // ebx
v2 = 0;
result = strlen(a1);
if ( result )
{
v4 = a1 - v1;
do
{
*v1 = byte_402FF8[(char)v1[v4]];
++v2;
++v1;
result = strlen(a1);
}
while ( v2 < result );
}
return result;
}
以上为IDA反汇编结果,因为涉及到指针的计算,直接从反汇编代码中无法理解 v1
v4
的作用,所以打开OD进行动态调试。
通过调试发现,v4的值是定值 sub ebx,ecx ⇒ ebx = 0x400
循环中,eax中存放一个byte的数据,来自ds:[ebx + ecx]
发现 ebx(0x400) + 0xecx
ecx每次都自增1,这正好是我们输入字符串的地址。
总结过程:
遍历输入的字符串,获取每个字符转为整数A,在常数数组获取下标为A的字符放入*V1中,每次V1指针都自增1
发现通过OD无法直接访问到0x402FF8
数据,但是访问 eax + 0x402FF8可以访问到数据,可以看出是一个字符串,所以直接在IDA中查看String,发现真正的地址为0x00403018
,存在0x20
的位移
通过IDA获取加密字符串
.data:00403018 00000060 C ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#\"!
通过以上分析,重写反汇编代码,让自己可以直接调试这个算法。
#include<iostream>
#include<string>
using namespace std;
string byte_402FF8 = "~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#\"! ";
unsigned int sub_401000(string inputArray)
{
char v1[100] = {0}; // result
unsigned int cnt = 0;
unsigned int inputLen = inputArray.length();
cnt = 0;
do
{
v1[cnt] = byte_402FF8[(char)inputArray[cnt] - 0x20];
++cnt;
}
while ( cnt < inputLen );
v1[cnt] = '\0';
cout <<v1;
return inputLen;
}
int main(){
sub_401000("123456");
}
最后运算结果与字符串DDCTF{reverseME}
比较是否相等
0x3 写脚本
我们要做的就是将字符串 DDCTF{reverseME}
重新映射到输入
#include<iostream>
#include<string>
using namespace std;
string byte_402FF8 = "~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#\"! ";
unsigned int sub_401000(string inputArray)
{
char v1[100] = {0}; // result
unsigned int cnt = 0;
unsigned int inputLen = inputArray.length();
cnt = 0;
do
{
v1[cnt] = byte_402FF8[(char)inputArray[cnt] - 0x20];
++cnt;
}
while ( cnt < inputLen );
v1[cnt] = '\0';
cout <<v1;
return inputLen;
}
int find_index(char s){
for(int i=0;i<byte_402FF8.length();i++){
if(s == byte_402FF8[i]) return i;
}
cout <<"error"<<endl;
return -1;
}
string reverse(string result){
char input[100];
int i;
for(i = 0; i < result.length() ;i++){
int index = find_index(result[i]);
input[i] = (char)index + 0x20;
}
input[i] = '\0';
return string(input);
}
int main(){
string flag = reverse("DDCTF{reverseME}");
cout << endl << "flag{" << flag << "}" << endl;
sub_401000(flag);
}
拿到flag
花了好长时间哇,中途去上数据库网课了哈哈。