170927 逆向-Reversing.kr(Position)

来源:互联网 发布:淘宝文胸模特赵小姐 编辑:程序博客网 时间:2024/06/08 09:06

1625-5 王子昂 总结《2017年9月27日》 【连续第360天总结】
A. Reversing.kr-Position
B.

Position

惯例先查壳
读Readme可以知道是一个检查Name-Serial的程序,我们需要找到对应Serial为”76876-77776”的Name

由于是个GUI程序,只能依靠API或者字符串来定位事件
IDA中没有找到对应的字符串,很是神奇
在OD中搜索却正常能搜索到,于是定位到核心事件函数sub_401740

由于函数太长就不放全部的了,基本上是同一个结构:

  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:

f = []for i in range(len(name)):    if i%2 :        o = 1    else:        o = 5    i = ord(s[i])    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[i]] + f[1][b[i]] ), end='')#前五位print('-', end='')for i in range(5):    print(( f[2][a[i]] + f[3][b[i]] ), 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

写脚本分别输出

flag =[[0b1100010, 0b1110101],[0b1100011, 0b1110100],[0b1100111, 0b1110000],[0b1100100, 0b1110001]]for i in flag:    print(chr(i[0])+chr(i[1])+'mp')

bump
ctmp
gpmp
dqmp

第一个是有意义的单词,输入程序验证果然Correct
完成

除了爆破好像没想到什么快速逆向的思路(:з」∠)有大佬做过的话希望能指点一下~

C. 明日计划
Reversing.kr

原创粉丝点击