好友
阅读权限30
听众
最后登录1970-1-1
|
本帖最后由 whklhh 于 2018-9-13 14:29 编辑
Reversing.kr是韩国的一个逆向题目网站
有分国度的排行榜,还是挺有意思的
本题即来自于第六关Position
http://reversing.kr/challenge.php可以下载到文件
Position
惯例先查壳
读Readme可以知道是一个检查Name-Serial的程序,我们需要找到对应Serial为”76876-77776”的Name
由于是个GUI程序,只能依靠API或者字符串来定位事件
IDA中没有找到对应的字符串,很是神奇
在OD中搜索却正常能搜索到,于是定位到核心事件函数sub_401740
由于函数太长就不放全部的了,基本上是同一个结构:
[C++] 纯文本查看 复制代码 ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&Name);
v1 = 0;
v64 = 0;
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&Serial);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v63);
LOBYTE(v64) = 2;
CWnd::GetWindowTextW(a1 + 304, &Name); // Name
if ( *(_DWORD *)(Name - 12) == 4 ) // Name长度为4
{
i = 0;
while ( (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&Name, i) >= 0x61u
&& (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&Name, i) <= 0x7Au )// 字母
{
if ( ++i >= 4 ) // 4个都为字母
{
LABEL_8:
v5 = 0;
while ( 1 )
{
if ( v1 != v5 )
{
v6 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&Name, v5);
if ( (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&Name, v1) == v6 )// 4个字母各不相同
goto Fail;
}
if ( ++v5 >= 4 )
{
if ( ++v1 < 4 )
goto LABEL_8; // 4个字母各不相同
CWnd::GetWindowTextW(a1 + 420, &Serial);
if ( *(_DWORD *)(Serial - 12) != 11 // Serial长度为11
|| (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&Serial, 5) != 45 )// 第六个字符为-
{
goto Fail;
}
v7 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&Name, 0);
v8 = (v7 & 1) + 5;
v59 = ((v7 >> 4) & 1) + 5;
v53 = ((v7 >> 1) & 1) + 5;
v55 = ((v7 >> 2) & 1) + 5;
v57 = ((v7 >> 3) & 1) + 5;
v9 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&Name, 1);
v45 = (v9 & 1) + 1;
v51 = ((v9 >> 4) & 1) + 1;
v47 = ((v9 >> 1) & 1) + 1;
v10 = ((v9 >> 2) & 1) + 1;
v49 = ((v9 >> 3) & 1) + 1;
v11 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v63);
itow_s(v8 + v10, v11, 0xAu, 10); // 将v8+v10放入v11中
v12 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v63, 0);
v13 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&Serial, 0);
v2 = &v63;
if ( v13 == v12 )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v63, -1);
v14 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v63);
itow_s(v57 + v49, v14, 0xAu, 10);
v15 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&Serial, 1);
v16 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v63, 0);
v2 = &v63;
if ( v15 == v16 )
{
流程虽然长但是挺简单的:
首先校对Name为4个各不相同的小写字母
然后按顺序取前5位二进制,第1、3个字母的数各+5,2、4个字母的数各+1
然后分别按特定顺序进行相加组合,并校对
第1、2个字母生成前五位,第3、4个字母生成后五位
如abcd
对应的前五位分别为00001, 00010, 00011, 00100
加常数并改变顺序(逆序后将第五位移至第二位)后得到结果
65555, 11211, 65655, 11121
然后按特定顺序相加
65555
11211
→76667
65655
11121
→86766
所以最终的Serial为76667-89766
很容易写出来KeyGen:
[Python] 纯文本查看 复制代码 f = []
for i in range(len(name)):
if i%2 :
o = 1
else:
o = 5
i = ord(s)
f0 = []
f0.append((i & 1) + o)
f0.append(((i >> 4) & 1) + o)
f0.append(((i >> 1) & 1) + o)
f0.append(((i >> 2) & 1) + o)
f0.append(((i >> 3) & 1) + o)
f.append(f0)
a=[0, 4, 2, 3, 1]#顺序由IDA中分析得来
b=[3, 4, 1, 0, 2]
for i in range(5):
print(( f[0][a] + f[1][b] ), end='')#前五位
print('-', end='')
for i in range(5):
print(( f[2][a] + f[3][b] ), end='')#后五位
接着考虑逆向,要求Serial为76876-77776
思考了一下这里是按位操作,还有多种可能,没想到什么快捷写脚本的方法,就乖乖数学解题吧
我们知道每个位都经过了a组的+5和b组的+1,所以实际上说明它们的对应位和应该是
10210-11110
这其中特殊的是0和2,意味着对应位分别都是0和都是1;关键在于1是哪个字母带来的
Name到Serial一共经过了3步变换:
1.取前五位ASCII并加常数5/1
2.改变顺序(逆序后将第五位放至第二位)
3.分别取两个字母的特定位置数相加逐步逆向:
首先知道提示中说了最后一个字母是’p’,Serial和为10210-11110
将p输入正向脚本可以得到12111,即01000
相加的顺序按照b组对应为00100
则能知道另一半的和为11010
按照a组顺序(04231)还原得到10011
将第二位还原至第五位然后逆序,得到01101
则第三个字母的ASCII为0b1101101,即109,即’m’
然后是前两个字母,这次虽然没提示,但是由于2和0的特性,可以大大减小可能的情况:
一共有2个1,即最多出现2x2=4种情况,可以接受
两个数的格式必然为x01y0(两个x中必然一个是1一个是0,y同理)
分别按照a组和b组的顺序还原:
a:
x01y0
x1y00
00y1x
b:
y10x0
y0x01
10x0y
则可能的格式有:
a,b
00010, 10101
00011, 10100
00111, 10000
00100, 10001
写脚本分别输出
[Python] 纯文本查看 复制代码 flag =[[0b1100010, 0b1110101],[0b1100011, 0b1110100],[0b1100111, 0b1110000],[0b1100100, 0b1110001]]
for i in flag:
print(chr(i[0])+chr(i[1])+'mp')
第一个是有意义的单词,输入程序验证果然Correct
完成
除了爆破好像没想到什么快速逆向的思路_(:з」∠)_有大佬做过的话希望能指点一下~
勘误:
xy对应错误,导致两个结果错位
感谢@a378151881的指证
则可能的格式有:
a,b
00010, 10101
00110, 10100
00111, 10000
00011, 10001
写脚本分别输出
[Python] 纯文本查看 复制代码 flag =[[0b1100010, 0b1110101],[0b1100011, 0b1110100],[0b1100111, 0b1110000],[0b1100100, 0b1110001]]
for i in flag:
print(chr(i[0])+chr(i[1])+'mp')
|
免费评分
-
查看全部评分
|