吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4667|回复: 12
收起左侧

[原创] 【Reversing.kr】Position

[复制链接]
whklhh 发表于 2017-9-27 22:53
本帖最后由 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')

bump
ctmp
gpmp
dqmp

第一个是有意义的单词,输入程序验证果然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')

bump
ftmp
gpmp
cqmp

Position.zip

64.44 KB, 下载次数: 4, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 3吾爱币 +8 热心值 +3 收起 理由
2864095098 + 1 + 1 热心回复!
lies2014 + 1 + 1 用心讨论,共获提升!
Sound + 6 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

a378151881 发表于 2018-9-12 21:37
虽然帖子时间很长了,但是楼主好像算出来的结果应该有错误
我算出来的是
bump
cqmp
ftmp
gpmp
这四组符合结尾是p(手动算过一遍)

有不对的地方请指出 下面是我的代码(有点长,太菜了):
a1 = []
a2 = []
a3 = []
a4 = []
a5 = []

b1 = []
b2 = []
b3 = []
b4 = []
b5 = []

c = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']

serial_1 = '76876'
serial_2 = '77776'
s_buf1 = ''
s_buf2 = ''
s1 = []
s2 = []

for c1 in range(0x61,0x7b):
        #print c1
    a1.append( (c1 & 0x1) + 5 )
    a2.append( ((c1 >> 1)&0x1) + 5 )
    a3.append( ((c1 >> 2)&0x1) + 5 )
    a4.append( ((c1 >> 3)&0x1) + 5 )
    a5.append( ((c1 >> 4)&0x1) + 5 )

    b1.append( (c1 & 0x1) + 1 )   
    b2.append( ((c1 >> 1)&0x1) + 1 )
    b3.append( ((c1 >> 2)&0x1) + 1 )
    b4.append( ((c1 >> 3)&0x1) + 1 )
    b5.append( ((c1 >> 4)&0x1) + 1 )

for i in range(26):
        for j in range(26):
                sum1 = a1[i] + b3[j]
                sum2 = a4[i] + b4[j]
                sum3 = a2[i] + b5[j]
                sum4 = a3[i] + b1[j]
                sum5 = a5[i] + b2[j]
                s_buf1 = str(sum1)+str(sum2)+str(sum3)+str(sum4)+str(sum5)
                if s_buf1 == serial_1 :
                        s1.append(c[i]+c[j])

        for j in range(26):
                sum1 = a1[i] + b3[j]
                sum2 = a4[i] + b4[j]
                sum3 = a2[i] + b5[j]
                sum4 = a3[i] + b1[j]
                sum5 = a5[i] + b2[j]
                s_buf2 = str(sum1)+str(sum2)+str(sum3)+str(sum4)+str(sum5)
                if s_buf2 == serial_2 :
                        s2.append(c[i]+c[j])

for i in range(len(s1)):
        for j in range(len(s2)):
                print s1[i]+s2[j]

 楼主| whklhh 发表于 2018-9-13 14:31
a378151881 发表于 2018-9-12 21:37
虽然帖子时间很长了,但是楼主好像算出来的结果应该有错误
我算出来的是
bump

=-=你是对的,我xy对应错了,导致两个结果错位 手输比特就错了嘿嘿 感谢指证~
不过测试了一下gpmp输入程序里是不符合的 说明还有咱俩没考虑到的东西~
msxw888 发表于 2017-9-27 23:06
davae 发表于 2017-9-27 23:18
牛牪犇逼
2864095098 发表于 2017-9-28 00:07
这算法得学习一下
都同学 发表于 2017-9-29 00:59
学习一波~
gunxsword 发表于 2017-10-13 19:50
66666666正向算KEY还好理解,反过来推出这个NAME,就真的有点烦了,数学不好.楼主实在历害!
无名侠 发表于 2018-2-3 02:11
厉害厉害,我只会用z3.。
欧琪茵 发表于 2018-2-5 13:22
学习一波。。。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-17 01:56

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表