一、learn-1
idea字符串定位
通过一下操作可以获取一个字符串列表,列表中的字符串都会被程序使用。
定位字符串
定位引用字符串的代码
伪代码分析
使用tab或者f5获取伪代码
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
char Str1[260]; // [esp+D0h] [ebp-108h] BYREF
sub_456502("Hi CTFer,Input your flag:");
sub_4554EF("%s", Str1);
if ( !j__strcmp(Str1, "flag{YOU_FIND_IT}") )
sub_456502("you are right!n");
else
sub_456502("you are wrong!n");
return 0;
}
-
sub_456502:
函数名,ida按照函数所在的内存地址将某些函数进行重命名。
ida将函数重命名
二、learn-2
ida搜索函数名称
搜索main函数发现有两个main函数
在main函数中调用了main0函数
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t i; // [esp+D0h] [ebp-114h]
char Str1[260]; // [esp+DCh] [ebp-108h] BYREF
sub_456502("Hi CTFer,Input your flag:");
sub_4554EF("%s", Str1);
for ( i = 0; i < j__strlen(Str1); ++i )
++Str1[i];
if ( !j__strcmp(Str1, "gmbh|ZPV`GJOE`JU`IBIB~") )
sub_456502("you are right!n");
else
sub_456502("you are wrong!n");
return 0;
}
使用python获取flag
flag_encode = "gmbh|ZPV`GJOE`JU`IBIB~"
flag=""
for i in flag_encode:
flag+=chr(ord(i)-1)
print(flag)
三、learn-3
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t i; // [esp+D0h] [ebp-114h]
char Str1[260]; // [esp+DCh] [ebp-108h] BYREF
sub_456502("[5] Hi CTFer,Input your flag:");
sub_4554EF("%s", Str1);
for ( i = 0; i < j__strlen(Str1); ++i )
Str1[i] ^= i;
if ( !j__strcmp(Str1, Str2) )
sub_456502("you are right!n");
else
sub_456502("you are wrong!n");
return 0;
}
ida查看全局变量
提取局部变量
flag_list = [0x66, 0x6D, 0x63, 0x64, 0x7F, 0x5C, 0x49, 0x52, 0x57, 0x4F, 0x43, 0x45, 0x48, 0x52, 0x47, 0x5B, 0x4F, 0x59, 0x53, 0x5B, 0x55, 0x68]
flag=""
for i,v in enumerate(flag_list):
flag+=chr(int(v)^i)
print(flag)
四、learn-4
base64编码逆向
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t v3; // eax
size_t i; // [esp+190h] [ebp-31Ch]
char Str1[520]; // [esp+19Ch] [ebp-310h] BYREF
char Str[260]; // [esp+3A4h] [ebp-108h] BYREF
sub_45650C("[4] Hi CTFer,Input your flag:");
sub_4554EF("%s", Str);
for ( i = 0; i < j__strlen(Str); ++i )
Str[i] ^= i;
v3 = j__strlen(Str);
sub_455A94(Str, Str1, v3);
if ( !j__strcmp(Str1, "Zm1jZH9cSVJXT0NFSFJHW09ZU1tVaA==") )
sub_45650C("you are right!n");
else
sub_45650C("you are wrong!n");
return 0;
}
获取字符串->异或->base64编码
import base64
flag_encode = base64.b64decode("Zm1jZH9cSVJXT0NFSFJHW09ZU1tVaA==")
flag=""
for i,v in enumerate(flag_encode):
flag+=chr(v^i)
print(flag)
五、learn-5
base64变表逆向
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t v3; // eax
size_t i; // [esp+190h] [ebp-31Ch]
char Str1[520]; // [esp+19Ch] [ebp-310h] BYREF
char Str[260]; // [esp+3A4h] [ebp-108h] BYREF
sub_45650C("[4] Hi CTFer,Input your flag:");
sub_4554EF("%s", Str);
for ( i = 0; i < j__strlen(Str); ++i )
Str[i] ^= i;
v3 = j__strlen(Str);
sub_455A94(Str, Str1, v3);
if ( !j__strcmp(Str1, "Wj1gWE9xPSGUQ0KCPCGET09WR1qSzZ==") )
sub_45650C("you are right!n");
else
sub_45650C("you are wrong!n");
return 0;
}
查看base64编码表
import base64
t5 = "ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/"
t4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
flag_encode = "Wj1gWE9xPSGUQ0KCPCGET09WR1qSzZ"
flag = ""
resault = ""
for i,v in enumerate(flag_encode):
position = t5.find(v)
resault+=t4[position]
resault = base64.b64decode(resault+"==")
for i,v in enumerate(resault):
flag +=chr(v^i)
print(flag)
base64在变表的过程中,==是不变的。
六、learn-6
ida动态调试
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t i; // [esp+190h] [ebp-340h]
char Str2[264]; // [esp+3A4h] [ebp-12Ch] BYREF
char Str1[32]; // [esp+4ACh] [ebp-24h] BYREF
qmemcpy(Str1, &unk_105DE50, 0x1Cu);
sub_FA9511("[6] Hi CTFer,Input your flag:");
sub_FA8521("%s", Str2);
for ( i = 0; i < j__strlen(Str1); ++i )
Str1[i] = ((i + 1) ^ Str1[i]) - i;
if ( !j__strcmp(Str1, Str2) )
sub_FA9511("you are rightn");
else
sub_FA9511("you are wrongn");
return 0;
}
分析程序得知str1为用户手动输入,str2是程序自己通过代码生成。
通过动态调试获取str2的值,定位str1的值
七、learn-7
ida绕过反调试
ida使用以下函数反调试
可以看到反调试函数位于printf函数之前,只要执行到printf函数位置在进行调试即可
启动调试exe,调试正在运行的进程
输入数据即可进行调试
常见加密算法破解
__int64 sub_140009385()
{
unsigned int v0; // ebx
unsigned int v1; // esi
int v2; // eax
char Str[8]; // [rsp+20h] [rbp-60h] BYREF
__int64 v5; // [rsp+28h] [rbp-58h]
__int64 v6; // [rsp+30h] [rbp-50h]
__int64 v7; // [rsp+38h] [rbp-48h]
__int64 v8; // [rsp+40h] [rbp-40h]
__int64 v9; // [rsp+48h] [rbp-38h]
__int64 v10; // [rsp+50h] [rbp-30h]
__int64 v11; // [rsp+58h] [rbp-28h]
__int64 v12; // [rsp+60h] [rbp-20h]
__int64 v13; // [rsp+68h] [rbp-18h]
int v14[258]; // [rsp+70h] [rbp-10h] BYREF
__int64 (__fastcall *v15)(); // [rsp+478h] [rbp+3F8h]
int m; // [rsp+484h] [rbp+404h]
int v17; // [rsp+488h] [rbp+408h]
int k; // [rsp+48Ch] [rbp+40Ch]
int j; // [rsp+490h] [rbp+410h]
int i; // [rsp+494h] [rbp+414h]
unsigned int v21; // [rsp+498h] [rbp+418h]
int length; // [rsp+49Ch] [rbp+41Ch]
sub_140009810();
memset(v14, 0, 0x400ui64);
v15 = 0i64;
*(_QWORD *)Str = 0i64;
v5 = 0i64;
v6 = 0i64;
v7 = 0i64;
v8 = 0i64;
v9 = 0i64;
v10 = 0i64;
v11 = 0i64;
v12 = 0i64;
v13 = 0i64;
v21 = 1;
srand(0); // 参数为0,所以每次生成的v14是相同的 。
//
for ( i = 0; i <= 95; ++i )
{
v15 = funcs_1400094C9[rand() % 256];
v0 = rand() % 0xFFFFF;
v1 = (unsigned __int16)rand();
v2 = rand();
v14[i] = ((__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD))v15)((unsigned int)(v2 % 4095), v1, v0);
}
for ( j = 0; j <= 31; ++j )
{
v15 = funcs_1400094C9[rand() % 256]; // v15是个指针,v14由随机数而来
//
v14[j] = ((__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD))v15)(
(unsigned int)v14[j],
(unsigned int)v14[j + 32],
(unsigned int)v14[j + 64]);
}
puts("Please input your flag: ");
sub_140001550("%50s", Str);
length = strlen(Str);
if ( Str[length - 1] == 10 )
Str[--length] = 0;
if ( length == 32 ) // 如果不是32就是跳出循环
//
{
for ( k = 0; k < length - 1; ++k ) // 0-31 的循环
{
v17 = k;
for ( m = 0; m <= 8; ++m ) // 计算v17 从0-8进行循环 v17是0-31的数字
v17 = k * k * k * k * v17 % 31; // v17是变化的
if ( Str[v17] == v14[k] ) // 输入字符串 位置就是v17 v14
v21 *= Str[v17];
else
v21 = 0;
}
v21 >>= 28;
if ( v21 && Str[length - 1] == a0123456789abcd[v21] )
{
sub_1400015A1("Yes, your got it, flag is flag{%s}n", Str);
return 0i64;
}
else
{
puts("Invalid flag, Please try again.");
return 0xFFFFFFFFi64;
}
}
else
{
puts("Invalid len");
return 0xFFFFFFFFi64;
}
}
for循环是0-31,没有计算第三十二位。
for ( k = 0; k < length - 1; ++k ) // 0-31 的循环
{
v17 = k;
for ( m = 0; m <= 8; ++m ) // 计算v17 从0-8进行循环 v17是0-31的数字
v17 = k * k * k * k * v17 % 31; // v17是变化的
if ( Str[v17] == v14[k] ) // 输入字符串 位置就是v17 v14
v21 *= Str[v17];
else
v21 = 0;
}
逆出算法
1、str为输入的值
2、v14为固定值,因为Srand(0)
3、v14函数里面定义 应该为局部变量
局部变量 在栈里
__int64 sub_7FF7A22E9385()
{
unsigned int v0; // ebx
unsigned int v1; // esi
int v2; // eax
char Str[8]; // [rsp+20h] [rbp-60h] BYREF
__int64 v5; // [rsp+28h] [rbp-58h]
__int64 v6; // [rsp+30h] [rbp-50h]
__int64 v7; // [rsp+38h] [rbp-48h]
__int64 v8; // [rsp+40h] [rbp-40h]
__int64 v9; // [rsp+48h] [rbp-38h]
__int64 v10; // [rsp+50h] [rbp-30h]
__int64 v11; // [rsp+58h] [rbp-28h]
__int64 v12; // [rsp+60h] [rbp-20h]
__int64 v13; // [rsp+68h] [rbp-18h]
int v14[258]; // [rsp+70h] [rbp-10h] BYREF
__int64 (__fastcall *v15)(); // [rsp+478h] [rbp+3F8h]
int m; // [rsp+484h] [rbp+404h]
int v17; // [rsp+488h] [rbp+408h]
int k; // [rsp+48Ch] [rbp+40Ch]
int j; // [rsp+490h] [rbp+410h]
int i; // [rsp+494h] [rbp+414h]
unsigned int v21; // [rsp+498h] [rbp+418h]
int length; // [rsp+49Ch] [rbp+41Ch]
sub_7FF7A22E9810();
memset(v14, 0, 0x400ui64);
v15 = 0i64;
*(_QWORD *)Str = 0i64;
v5 = 0i64;
v6 = 0i64;
v7 = 0i64;
v8 = 0i64;
v9 = 0i64;
v10 = 0i64;
v11 = 0i64;
v12 = 0i64;
v13 = 0i64;
v21 = 1;
srand(0); // 参数为0,所以每次生成的v14是相同的 。
//
for ( i = 0; i <= 95; ++i )
{
v15 = funcs_1400094C9[rand() % 256];
v0 = rand() % 0xFFFFF;
v1 = (unsigned __int16)rand();
v2 = rand();
v14[i] = ((__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD))v15)((unsigned int)(v2 % 4095), v1, v0);
}
for ( j = 0; j <= 31; ++j )
{
v15 = funcs_1400094C9[rand() % 256]; // v15是个指针,v14由随机数而来
//
v14[j] = ((__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD))v15)(
(unsigned int)v14[j],
(unsigned int)v14[j + 32],
(unsigned int)v14[j + 64]);
}
puts("Please input your flag: ");
sub_7FF7A22E1550("%50s", Str);
length = strlen(Str);
if ( Str[length - 1] == 10 )
Str[--length] = 0;
if ( length == 32 ) // 如果不是32就是跳出循环
//
{
for ( k = 0; k < length - 1; ++k ) // 0-31 的循环
{
v17 = k;
for ( m = 0; m <= 8; ++m ) // 计算v17 从0-8进行循环 v17是0-31的数字
v17 = k * k * k * k * v17 % 31; // v17是变化的
if ( Str[v17] == v14[k] ) // 输入字符串 位置就是v17 v14
v21 *= Str[v17];
else
v21 = 0;
}
v21 >>= 28; // 21是三十二位的右移动28位 最后的范围为0-15。2的4次方可能性
if ( v21 && Str[length - 1] == a0123456789abcd[v21] )// v21正好也是16个数字 全局变量也是16个 先运算等于号 在是与 v21是11 输入的字符串最后应该为c
{
sub_7FF7A22E15A1("Yes, your got it, flag is flag{%s}n", Str);
return 0i64;
}
else
{
puts("Invalid flag, Please try again.");
return 0xFFFFFFFFi64;
}
}
else
{
puts("Invalid len");
return 0xFFFFFFFFi64;
}
}
八、某省赛-ez_base32.exe
打开exe,shift+fn+f12,搜索字符串。
找到对应的汇编代码
control+x找到引用字符串的函数
F5查看伪代码
原文始发于微信公众号(土拨鼠的安全屋):逆向学习 |实操小练
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论