-
-
[原创]南邮ctf逆向single
-
发表于: 2019-2-19 18:14 4042
-
1.elf64位程序,直接使用ida进行分析,搜索关键字符串进行定位分析,将输入字符串经过一系列变换之后输出。详细的分析在下面
__int64 __fastcall main(__int64 a1, char **a2, char **a3) { char s; // [rsp+0h] [rbp-70h] unsigned __int64 v5; // [rsp+68h] [rbp-8h] v5 = __readfsqword(0x28u); memset(&s, 0, 0x64uLL); puts("Input string:"); scanf("%s", &s); sub_40070E(&s);//数据长度不能大于0x51,输入的数据大于47小于等于57 sub_40078B(&s, (__int64)&unk_602080); sub_400AD4((__int64)&unk_602080); puts("Congratulations!"); printf("flag{%s}", &s); return 0LL; }
2.首先分析40070e函数:
size_t __fastcall sub_40070E(const char *a1) { size_t result; // rax int i; // [rsp+1Ch] [rbp-14h] if ( strlen(a1) > 0x51 )//输入的长度不能大于0x51 sub_4006F6();//这个函数是错误标志 for ( i = 0; ; ++i ) { result = strlen(a1); if ( i >= result ) break; if ( a1[i] <= 47 || a1[i] > 57 )//输入的数据必须大于47和小于等于57,这里是进行数据范围的限制 0,1,2,3,4,5,6,7,8,9 sub_4006F6();//错误标志 } return result; }
2.对40078b函数进行分析,传入unk_602080进行操作。
size_t __fastcall sub_40078B(const char *a1, __int64 a2) { size_t result; // rax int i; // [rsp+1Ch] [rbp-14h] for ( i = 0; ; ++i ) { result = strlen(a1); if ( i >= result ) break; if ( a1[i] != 48 ) //当a[i]=0的时候可以跳过相应的检测,所以对a2[i]=0的地方应该让a[i]=0 { if ( !a1[i] || *(_BYTE *)(i + a2) ) //a2[i]!=0 sub_4006F6(); *(_BYTE *)(i + a2) = a1[i] - 48;//a1[i]-48存入602080处,将字符串转换成数字0,1,2,3,4,5,6,7,8 } } return result; }
4.函数400ad4里面又是另外的两个函数
unsigned __int64 __fastcall sub_400AD4(__int64 a1) { sub_400833(a1); sub_4008FE(a1); return sub_4009C9(a1); }
5.分析400833函数,这段代码很有迷惑性,需要认真的分析
unsigned __int64 __fastcall sub_400833(__int64 a1) { signed int i; // [rsp+18h] [rbp-28h] signed int j; // [rsp+1Ch] [rbp-24h] signed int k; // [rsp+1Ch] [rbp-24h] char s[24]; // [rsp+20h] [rbp-20h] unsigned __int64 v6; // [rsp+38h] [rbp-8h] v6 = __readfsqword(0x28u); for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); //这里将数组s都初始化为零 for ( j = 0; j <= 8; ++j ) ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++ for ( k = 1; k <= 9; ++k ) { if ( s[k] != 1 ) //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9 sub_4006F6(); } } return __readfsqword(0x28u) ^ v6; }
4008fe函数同理可得,用来判断每列都必须包含1-9
6.下面对4009e9进行分析
unsigned __int64 __fastcall sub_4009C9(__int64 a1) { signed int i; // [rsp+1Ch] [rbp-34h] int j; // [rsp+20h] [rbp-30h] signed int l; // [rsp+20h] [rbp-30h] int k; // [rsp+24h] [rbp-2Ch] signed int v6; // [rsp+28h] [rbp-28h] signed int v7; // [rsp+2Ch] [rbp-24h] char s[24]; // [rsp+30h] [rbp-20h] unsigned __int64 v9; // [rsp+48h] [rbp-8h] v9 = __readfsqword(0x28u); v6 = 3; v7 = 3; for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); for ( j = v6 - 3; j < v6; ++j ) { for ( k = v7 - 3; k < v7; ++k ) ++s[*(unsigned __int8 *)(9 * j + k + a1)];//这里分为3*3的数组进行判断,每个3*3数组里面必须包含1-9. } for ( l = 1; l <= 9; ++l ) { if ( s[l] != 1 ) sub_4006F6(); } if ( v7 == 9 ) { v7 = 3; v6 += 3; } else { v7 += 3; } } return __readfsqword(0x28u) ^ v9; }
总的来说,就是一个简单的数组游戏,9个3*3的数组组成一个9*9的大数组,每个小数组必须包含1-9,大数组每行必须包含1-9,每列必须包含1-9
最后求解处答案,原先初始的地方应该置为零
最后得到答案:
flag{401095728057800001802040305000321589500479002923586000105060203300008950269750804}
解题代码见附件
__int64 __fastcall main(__int64 a1, char **a2, char **a3) { char s; // [rsp+0h] [rbp-70h] unsigned __int64 v5; // [rsp+68h] [rbp-8h] v5 = __readfsqword(0x28u); memset(&s, 0, 0x64uLL); puts("Input string:"); scanf("%s", &s); sub_40070E(&s);//数据长度不能大于0x51,输入的数据大于47小于等于57 sub_40078B(&s, (__int64)&unk_602080); sub_400AD4((__int64)&unk_602080); puts("Congratulations!"); printf("flag{%s}", &s); return 0LL; }
2.首先分析40070e函数:
size_t __fastcall sub_40070E(const char *a1) { size_t result; // rax int i; // [rsp+1Ch] [rbp-14h] if ( strlen(a1) > 0x51 )//输入的长度不能大于0x51 sub_4006F6();//这个函数是错误标志 for ( i = 0; ; ++i ) { result = strlen(a1); if ( i >= result ) break; if ( a1[i] <= 47 || a1[i] > 57 )//输入的数据必须大于47和小于等于57,这里是进行数据范围的限制 0,1,2,3,4,5,6,7,8,9 sub_4006F6();//错误标志 } return result; }
2.对40078b函数进行分析,传入unk_602080进行操作。
size_t __fastcall sub_40078B(const char *a1, __int64 a2) { size_t result; // rax int i; // [rsp+1Ch] [rbp-14h] for ( i = 0; ; ++i ) { result = strlen(a1); if ( i >= result ) break; if ( a1[i] != 48 ) //当a[i]=0的时候可以跳过相应的检测,所以对a2[i]=0的地方应该让a[i]=0 { if ( !a1[i] || *(_BYTE *)(i + a2) ) //a2[i]!=0 sub_4006F6(); *(_BYTE *)(i + a2) = a1[i] - 48;//a1[i]-48存入602080处,将字符串转换成数字0,1,2,3,4,5,6,7,8 } } return result; }
4.函数400ad4里面又是另外的两个函数
unsigned __int64 __fastcall sub_400AD4(__int64 a1) { sub_400833(a1); sub_4008FE(a1); return sub_4009C9(a1); }
5.分析400833函数,这段代码很有迷惑性,需要认真的分析
unsigned __int64 __fastcall sub_400833(__int64 a1) { signed int i; // [rsp+18h] [rbp-28h] signed int j; // [rsp+1Ch] [rbp-24h] signed int k; // [rsp+1Ch] [rbp-24h] char s[24]; // [rsp+20h] [rbp-20h] unsigned __int64 v6; // [rsp+38h] [rbp-8h] v6 = __readfsqword(0x28u); for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); //这里将数组s都初始化为零 for ( j = 0; j <= 8; ++j ) ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++ for ( k = 1; k <= 9; ++k ) { if ( s[k] != 1 ) //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9 sub_4006F6(); } } return __readfsqword(0x28u) ^ v6; }
4008fe函数同理可得,用来判断每列都必须包含1-9
6.下面对4009e9进行分析
unsigned __int64 __fastcall sub_4009C9(__int64 a1) { signed int i; // [rsp+1Ch] [rbp-34h] int j; // [rsp+20h] [rbp-30h] signed int l; // [rsp+20h] [rbp-30h] int k; // [rsp+24h] [rbp-2Ch] signed int v6; // [rsp+28h] [rbp-28h] signed int v7; // [rsp+2Ch] [rbp-24h] char s[24]; // [rsp+30h] [rbp-20h] unsigned __int64 v9; // [rsp+48h] [rbp-8h] v9 = __readfsqword(0x28u); v6 = 3; v7 = 3; for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); for ( j = v6 - 3; j < v6; ++j ) { for ( k = v7 - 3; k < v7; ++k ) ++s[*(unsigned __int8 *)(9 * j + k + a1)];//这里分为3*3的数组进行判断,每个3*3数组里面必须包含1-9. } for ( l = 1; l <= 9; ++l ) { if ( s[l] != 1 ) sub_4006F6(); } if ( v7 == 9 ) { v7 = 3; v6 += 3; } else { v7 += 3; } } return __readfsqword(0x28u) ^ v9; }
总的来说,就是一个简单的数组游戏,9个3*3的数组组成一个9*9的大数组,每个小数组必须包含1-9,大数组每行必须包含1-9,每列必须包含1-9
最后求解处答案,原先初始的地方应该置为零
最后得到答案:
flag{401095728057800001802040305000321589500479002923586000105060203300008950269750804}
解题代码见附件
size_t __fastcall sub_40070E(const char *a1) { size_t result; // rax int i; // [rsp+1Ch] [rbp-14h] if ( strlen(a1) > 0x51 )//输入的长度不能大于0x51 sub_4006F6();//这个函数是错误标志 for ( i = 0; ; ++i ) { result = strlen(a1); if ( i >= result ) break; if ( a1[i] <= 47 || a1[i] > 57 )//输入的数据必须大于47和小于等于57,这里是进行数据范围的限制 0,1,2,3,4,5,6,7,8,9 sub_4006F6();//错误标志 } return result; }
2.对40078b函数进行分析,传入unk_602080进行操作。
size_t __fastcall sub_40078B(const char *a1, __int64 a2) { size_t result; // rax int i; // [rsp+1Ch] [rbp-14h] for ( i = 0; ; ++i ) { result = strlen(a1); if ( i >= result ) break; if ( a1[i] != 48 ) //当a[i]=0的时候可以跳过相应的检测,所以对a2[i]=0的地方应该让a[i]=0 { if ( !a1[i] || *(_BYTE *)(i + a2) ) //a2[i]!=0 sub_4006F6(); *(_BYTE *)(i + a2) = a1[i] - 48;//a1[i]-48存入602080处,将字符串转换成数字0,1,2,3,4,5,6,7,8 } } return result; }
4.函数400ad4里面又是另外的两个函数
unsigned __int64 __fastcall sub_400AD4(__int64 a1) { sub_400833(a1); sub_4008FE(a1); return sub_4009C9(a1); }
5.分析400833函数,这段代码很有迷惑性,需要认真的分析
unsigned __int64 __fastcall sub_400833(__int64 a1) { signed int i; // [rsp+18h] [rbp-28h] signed int j; // [rsp+1Ch] [rbp-24h] signed int k; // [rsp+1Ch] [rbp-24h] char s[24]; // [rsp+20h] [rbp-20h] unsigned __int64 v6; // [rsp+38h] [rbp-8h] v6 = __readfsqword(0x28u); for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); //这里将数组s都初始化为零 for ( j = 0; j <= 8; ++j ) ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++ for ( k = 1; k <= 9; ++k ) { if ( s[k] != 1 ) //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9 sub_4006F6(); } } return __readfsqword(0x28u) ^ v6; }
4008fe函数同理可得,用来判断每列都必须包含1-9
6.下面对4009e9进行分析
unsigned __int64 __fastcall sub_4009C9(__int64 a1) { signed int i; // [rsp+1Ch] [rbp-34h] int j; // [rsp+20h] [rbp-30h] signed int l; // [rsp+20h] [rbp-30h] int k; // [rsp+24h] [rbp-2Ch] signed int v6; // [rsp+28h] [rbp-28h] signed int v7; // [rsp+2Ch] [rbp-24h] char s[24]; // [rsp+30h] [rbp-20h] unsigned __int64 v9; // [rsp+48h] [rbp-8h] v9 = __readfsqword(0x28u); v6 = 3; v7 = 3; for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); for ( j = v6 - 3; j < v6; ++j ) { for ( k = v7 - 3; k < v7; ++k ) ++s[*(unsigned __int8 *)(9 * j + k + a1)];//这里分为3*3的数组进行判断,每个3*3数组里面必须包含1-9. } for ( l = 1; l <= 9; ++l ) { if ( s[l] != 1 ) sub_4006F6(); } if ( v7 == 9 ) { v7 = 3; v6 += 3; } else { v7 += 3; } } return __readfsqword(0x28u) ^ v9; }
总的来说,就是一个简单的数组游戏,9个3*3的数组组成一个9*9的大数组,每个小数组必须包含1-9,大数组每行必须包含1-9,每列必须包含1-9
最后求解处答案,原先初始的地方应该置为零
最后得到答案:
flag{401095728057800001802040305000321589500479002923586000105060203300008950269750804}
解题代码见附件
size_t __fastcall sub_40078B(const char *a1, __int64 a2) { size_t result; // rax int i; // [rsp+1Ch] [rbp-14h] for ( i = 0; ; ++i ) { result = strlen(a1); if ( i >= result ) break; if ( a1[i] != 48 ) //当a[i]=0的时候可以跳过相应的检测,所以对a2[i]=0的地方应该让a[i]=0 { if ( !a1[i] || *(_BYTE *)(i + a2) ) //a2[i]!=0 sub_4006F6(); *(_BYTE *)(i + a2) = a1[i] - 48;//a1[i]-48存入602080处,将字符串转换成数字0,1,2,3,4,5,6,7,8 } } return result; }
4.函数400ad4里面又是另外的两个函数
unsigned __int64 __fastcall sub_400AD4(__int64 a1) { sub_400833(a1); sub_4008FE(a1); return sub_4009C9(a1); }
5.分析400833函数,这段代码很有迷惑性,需要认真的分析
unsigned __int64 __fastcall sub_400833(__int64 a1) { signed int i; // [rsp+18h] [rbp-28h] signed int j; // [rsp+1Ch] [rbp-24h] signed int k; // [rsp+1Ch] [rbp-24h] char s[24]; // [rsp+20h] [rbp-20h] unsigned __int64 v6; // [rsp+38h] [rbp-8h] v6 = __readfsqword(0x28u); for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); //这里将数组s都初始化为零 for ( j = 0; j <= 8; ++j ) ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++ for ( k = 1; k <= 9; ++k ) { if ( s[k] != 1 ) //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9 sub_4006F6(); } } return __readfsqword(0x28u) ^ v6; }
4008fe函数同理可得,用来判断每列都必须包含1-9
6.下面对4009e9进行分析
unsigned __int64 __fastcall sub_4009C9(__int64 a1) { signed int i; // [rsp+1Ch] [rbp-34h] int j; // [rsp+20h] [rbp-30h] signed int l; // [rsp+20h] [rbp-30h] int k; // [rsp+24h] [rbp-2Ch] signed int v6; // [rsp+28h] [rbp-28h] signed int v7; // [rsp+2Ch] [rbp-24h] char s[24]; // [rsp+30h] [rbp-20h] unsigned __int64 v9; // [rsp+48h] [rbp-8h] v9 = __readfsqword(0x28u); v6 = 3; v7 = 3; for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); for ( j = v6 - 3; j < v6; ++j ) { for ( k = v7 - 3; k < v7; ++k ) ++s[*(unsigned __int8 *)(9 * j + k + a1)];//这里分为3*3的数组进行判断,每个3*3数组里面必须包含1-9. } for ( l = 1; l <= 9; ++l ) { if ( s[l] != 1 ) sub_4006F6(); } if ( v7 == 9 ) { v7 = 3; v6 += 3; } else { v7 += 3; } } return __readfsqword(0x28u) ^ v9; }
总的来说,就是一个简单的数组游戏,9个3*3的数组组成一个9*9的大数组,每个小数组必须包含1-9,大数组每行必须包含1-9,每列必须包含1-9
最后求解处答案,原先初始的地方应该置为零
最后得到答案:
flag{401095728057800001802040305000321589500479002923586000105060203300008950269750804}
解题代码见附件
unsigned __int64 __fastcall sub_400AD4(__int64 a1) { sub_400833(a1); sub_4008FE(a1); return sub_4009C9(a1); }
5.分析400833函数,这段代码很有迷惑性,需要认真的分析
unsigned __int64 __fastcall sub_400833(__int64 a1) { signed int i; // [rsp+18h] [rbp-28h] signed int j; // [rsp+1Ch] [rbp-24h] signed int k; // [rsp+1Ch] [rbp-24h] char s[24]; // [rsp+20h] [rbp-20h] unsigned __int64 v6; // [rsp+38h] [rbp-8h] v6 = __readfsqword(0x28u); for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); //这里将数组s都初始化为零 for ( j = 0; j <= 8; ++j ) ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++ for ( k = 1; k <= 9; ++k ) { if ( s[k] != 1 ) //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9 sub_4006F6(); } } return __readfsqword(0x28u) ^ v6; }
4008fe函数同理可得,用来判断每列都必须包含1-9
6.下面对4009e9进行分析
unsigned __int64 __fastcall sub_4009C9(__int64 a1) { signed int i; // [rsp+1Ch] [rbp-34h] int j; // [rsp+20h] [rbp-30h] signed int l; // [rsp+20h] [rbp-30h] int k; // [rsp+24h] [rbp-2Ch] signed int v6; // [rsp+28h] [rbp-28h] signed int v7; // [rsp+2Ch] [rbp-24h] char s[24]; // [rsp+30h] [rbp-20h] unsigned __int64 v9; // [rsp+48h] [rbp-8h] v9 = __readfsqword(0x28u); v6 = 3; v7 = 3; for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); for ( j = v6 - 3; j < v6; ++j ) { for ( k = v7 - 3; k < v7; ++k ) ++s[*(unsigned __int8 *)(9 * j + k + a1)];//这里分为3*3的数组进行判断,每个3*3数组里面必须包含1-9. } for ( l = 1; l <= 9; ++l ) { if ( s[l] != 1 ) sub_4006F6(); } if ( v7 == 9 ) { v7 = 3; v6 += 3; } else { v7 += 3; } } return __readfsqword(0x28u) ^ v9; }
总的来说,就是一个简单的数组游戏,9个3*3的数组组成一个9*9的大数组,每个小数组必须包含1-9,大数组每行必须包含1-9,每列必须包含1-9
最后求解处答案,原先初始的地方应该置为零
最后得到答案:
flag{401095728057800001802040305000321589500479002923586000105060203300008950269750804}
解题代码见附件
unsigned __int64 __fastcall sub_400833(__int64 a1) { signed int i; // [rsp+18h] [rbp-28h] signed int j; // [rsp+1Ch] [rbp-24h] signed int k; // [rsp+1Ch] [rbp-24h] char s[24]; // [rsp+20h] [rbp-20h] unsigned __int64 v6; // [rsp+38h] [rbp-8h] v6 = __readfsqword(0x28u); for ( i = 0; i <= 8; ++i ) { memset(s, 0, 0xAuLL); //这里将数组s都初始化为零 for ( j = 0; j <= 8; ++j ) ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++ for ( k = 1; k <= 9; ++k ) { if ( s[k] != 1 ) //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9 sub_4006F6(); } } return __readfsqword(0x28u) ^ v6; }
4008fe函数同理可得,用来判断每列都必须包含1-9
6.下面对4009e9进行分析
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
- [原创]angr/pyvex模块学习 8672
- [原创] Valgrind VEX IR 9196
- [原创]内存映射文件-进程间共享数据 11446
- [求助]C#反编译字符串出现乱码如何解决 4059
- [原创]windows dll注入/Api钩取技术简单总结 55862
谁下载
无
看原图
赞赏
雪币:
留言: