正常走,看到是一个32位的文件,无壳
然后先用IDA打开看看
其实,我打开看到代码蒙蒙的,很正常的用shift+f12看看字符串
但是还是一无所获【可能我菜鸡了】
然后又看了看main函数
感觉也对我来说也没有什么可以让我触动的地方
看了往上的WP后才知道 DialogFunc 这个函数有鬼
所以再main函数里面找到这个函数然后才开始了我的分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 INT_PTR __stdcall DialogFunc (HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) { const char *v4; const char *v5; int v7[2 ]; int v8; int v9; int v10; int v11; int v12; int v13; int v14; int v15; int v16; CHAR String[65536 ]; char v18[65536 ]; if ( a2 == 272 ) return 1 ; if ( a2 != 273 ) return 0 ; if ( (_WORD)a3 == 1001 ) { memset (String, 0 , 0xFFFF u); GetDlgItemTextA(hDlg, 1000 , String, 0xFFFF ); if ( strlen (String) == 8 ) { v7[0 ] = 90 ; v7[1 ] = 74 ; v8 = 83 ; v9 = 69 ; v10 = 67 ; v11 = 97 ; v12 = 78 ; v13 = 72 ; v14 = 51 ; v15 = 110 ; v16 = 103 ; sub_4010F0(v7, 0 , 10 ); memset (v18, 0 , 0xFFFF u); v18[0 ] = String[5 ]; v18[2 ] = String[7 ]; v18[1 ] = String[6 ]; v4 = (const char *)sub_401000(v18, strlen (v18)); memset (v18, 0 , 0xFFFF u); v18[1 ] = String[3 ]; v18[0 ] = String[2 ]; v18[2 ] = String[4 ]; v5 = (const char *)sub_401000(v18, strlen (v18)); if ( String[0 ] == v7[0 ] + 34 && String[1 ] == v10 && 4 * String[2 ] - 141 == 3 * v8 && String[3 ] / 4 == 2 * (v13 / 9 ) && !strcmp (v4, "ak1w" ) && !strcmp (v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 ); } } return 0 ; } if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 ) return 0 ; EndDialog(hDlg, (unsigned __int16)a3); return 1 ; }
看到的是这样一串东西,哇哦好多,好难受…
根据网上说的经验之谈,这个if语句肯定就是逆向的点,也就是说:这个地方
下面有2个字符串比较的函数,所以肯定有一个flag 经过某些操作后和这个strcmp比较,如果正确的话就是flag
也就是说,flag经过变换变成了ak1w 和 V1Ax。至于是如何变换来的,这个就需要分析上面的代码来看看了。
看代码,根据我的总结:首先粗略的看一下流程,大概知道这个是在讲什么的,然后再一步一步的慢慢 分析每一步的作用【当遇到某一步,不太好静态分析出来的时候就需要使用OD动态调试一下】
ok 我们现在来看看
首先他是定于了一大变量,然后就是进行if判断,但是这2个if对我们逆向这个点,没有太大的作用,因为他们if后都是return ;就返回了,肯定程序不能走这里,所以就没有分析的价值。
然后就是第三个if
这个if肯定有作用,因为后面的代码都是再这个if里面的
第一句,memset 就是拷贝
下一句调用了一个API函数,这里先跳过,因为我不知道这个API函数是作什么的,反正就是调用了某一个函数。
又是下一句 判断String 是否等于8 这里,必须等于8,不然就没有什么意义了
看到下面是给一堆的变量赋值,这里,凭着我的直觉,这些变量在某种程度上有一定的联系,返回去看看它定义的地方。果然,定义的地方都是在一起的,说明什么?说明这个是一个数组。
下面就是一个sub_4010f0的函数,点过去看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 int __cdecl sub_4010F0 (int a1, int a2, int a3) { int result; int i; int v5; int v6; result = a3; for ( i = a2; i <= a3; a2 = i ) { v5 = 4 * i; v6 = *(_DWORD *)(4 * i + a1); if ( a2 < result && i < result ) { do { if ( v6 > *(_DWORD *)(a1 + 4 * result) ) { if ( i >= result ) break ; ++i; *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result); if ( i >= result ) break ; while ( *(_DWORD *)(a1 + 4 * i) <= v6 ) { if ( ++i >= result ) goto LABEL_13; } if ( i >= result ) break ; v5 = 4 * i; *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1); } --result; } while ( i < result ); } LABEL_13: *(_DWORD *)(a1 + 4 * result) = v6; sub_4010F0(a1, a2, i - 1 ); result = a3; ++i; } return result; }
很明显,这个地方不好分析,我本身是准备用OD动态调试一下,看看这个地方到底是在干什么
但是由于我比较垃圾,调试不出来MD。
又去看了看WP , 发现它是它把重新写成了一个c代码,然后运行了一下
这里我们效仿一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <stdio.h> int __cdecl sub_4010F0 (int s[], int a2, int a3) { int result; int i; int v5; int v6; result = a3; for (i = a2; i <= a3; a2 = i) { v5 = i; v6 = s[i]; if (a2 < result && i < result) { do { if (v6 > s[result]) { if (i >= result) break ; ++i; s[v5] = s[result]; if (i >= result) break ; while (s[i] <= v6) { if (++i >= result) goto LABEL_13; } if (i >= result) break ; v5 = i; s[result] = s[i]; } --result; } while (i < result); } LABEL_13: s[result] = v6; sub_4010F0(s, a2, i - 1 ); result = a3; ++i; } return result; } int main () { int s[11 ] = { 'Z' ,'J' ,'S' ,'E' ,'C' ,'a' ,'N' ,'H' ,'3' ,'n' ,'g' }; sub_4010F0(s, 0 , 10 ); for (int i = 0 ; i < 11 ; i++) { printf ("%c" , s[i]); } }
这里看到
1 *(_DWORD *)(4 * i + a1);
这个是变成了
这里就不得不感谢一下
https://blog.csdn.net/afanzcf/article/details/119682630?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168562858016800226513434%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=168562858016800226513434&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-119682630-null-null.142^v88^control_2,239^v2^insert_chatgpt&utm_term=%E5%88%AE%E5%BC%80%E6%9C%89%E5%A5%96%20BUU&spm=1018.2226.3001.4187
这篇文章了
【这里不知道为什么,复制地址这么多….】
这里截取一下它的主要内容
也就是这个公式
所以在原本的IDA中编译出来是4*i
但是在原先定义的时候,是用int 定义的,所以这里是一个int类型的数组,所以就需要4*1
但是写出来的时候就是[i]
这样就知道原来的数组变成了:3CEHJNSZagn
对比一下之前的:ZJSECaNH3ng
很明显,这个是进行了一次排序。
接着往下看:看到一个初始化某个数组后,把这个数组放进了sub_401000函数
现在就是来看看sub_401000函数是干什么的
好吧,看了还是看不懂,本身想说利用上面的方法进行一次操作的
但是发现….【好吧,还是能力有限的问题】看了WP后知道,这里直接就猜到了base64编码
因为
这个
还有一种猜测的方式是:
进去的是3个字符,但是最后比较的是4个字符。
3个变成了4个 猜测base64
OK 我们现在知道了
解码
得到的是WP1 和jMp
加上上面的string[0]和[1]来进行分析咯
1 2 String[0] == v7[0] + 34 String[1] == v10
v7[0] = ‘3’ + 34 = 85 = ‘U’
v10 = ‘J’
所以flag{UJWP1jMp}
补充
这里可以用IDA的动调
也能得到这个
好舒服的IDA!!!!