逆向学习 |实操小练

admin 2024年10月30日14:18:29评论6 views字数 7646阅读25分29秒阅读模式

一、learn-1

idea字符串定位

通过一下操作可以获取一个字符串列表,列表中的字符串都会被程序使用。

逆向学习 |实操小练
image

定位字符串

逆向学习 |实操小练
image

定位引用字符串的代码

逆向学习 |实操小练
image

伪代码分析

使用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将函数重命名

逆向学习 |实操小练
image

二、learn-2

ida搜索函数名称

搜索main函数发现有两个main函数

逆向学习 |实操小练
image

在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查看全局变量

逆向学习 |实操小练
image

提取局部变量

逆向学习 |实操小练
image
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编码表

逆向学习 |实操小练
image
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是程序自己通过代码生成。

逆向学习 |实操小练
image

通过动态调试获取str2的值,定位str1的值

逆向学习 |实操小练
image

七、learn-7

ida绕过反调试

ida使用以下函数反调试

逆向学习 |实操小练
image

可以看到反调试函数位于printf函数之前,只要执行到printf函数位置在进行调试即可

逆向学习 |实操小练
image

启动调试exe,调试正在运行的进程

逆向学习 |实操小练
image

输入数据即可进行调试

逆向学习 |实操小练
image

常见加密算法破解

__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,搜索字符串。

逆向学习 |实操小练
image

找到对应的汇编代码

逆向学习 |实操小练
image

control+x找到引用字符串的函数

逆向学习 |实操小练
image

F5查看伪代码

逆向学习 |实操小练
image

原文始发于微信公众号(土拨鼠的安全屋):逆向学习 |实操小练

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月30日14:18:29
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   逆向学习 |实操小练http://cn-sec.com/archives/3333528.html

发表评论

匿名网友 填写信息