吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4984|回复: 9
收起左侧

[原创] 【Reversing.kr】Direct3D_FPS

[复制链接]
whklhh 发表于 2017-9-28 19:31
本帖最后由 whklhh 于 2017-11-14 15:14 编辑

Reversing.kr是韩国的一个逆向题目网站
有分国度的排行榜,还是挺有意思的
本题即来自于第七关Direct3D_FPS
http://reversing.kr/challenge.php可以下载到文件

这次DX让我有点怂……
一直对这种大型程序都心有畏惧,可能是因为没写过不了解其原理吧

解压出来可以看到包含一个DX库,一个Data文件夹下放置着各种图片和音效资源,一个exe
运行一打开就把我吓了一跳,差点以为不小心打开的恐怖游戏……

这囧囧的怪物,还有后面那张好像兵库北的微笑的图片

(:з」∠)惯例拖入IDA查找字符串,这次核心函数就在WinMain中
由于函数太长就不放全部内容了

大体上可以根据游戏画面中左下角显示的10和失败提示找到HP
根据枪声音效找到射击控制部分
根据按键的Switch结构找到移动部分
另外射击的后坐力和音效是有一定的间隔的,这意味着一定有一个计时器(否则将会不间断的连续产生枪声音效,很违和)

试玩了一下,很简陋不过五脏俱全了,基本上开5枪才能杀死一个怪;另外随着距离增加还有随机的散射效果

基本理清整个程序的结构,怪物和自己应该都是对象,在内存中各占132个字节
不过没分析清楚类的成员;只能看出来有存活标识和HP两部分

沿着GameClear!的字符串可以找到胜利检查函数:

[C++] 纯文本查看 复制代码
int *Is_win()
{
  int *result; // eax@1

  result = dword_E49194;//怪物[0]地址
  while ( *result != 1 )//遍历,发现有存活就跳出
  {
    result += 132;//指针指向下一个怪物
    if ( (signed int)result >= (signed int)&unk_E4F8B4 )//遍历完全
    {
      MessageBoxA(hWnd, "CkfkbuliLE\\E_ZF\x1C\a%%)p\x1749\x01\x16IL \x15\v\x0F麟褒爰籼跓躔栉皓", "Game Clear!", 0x40u);//显示flag
      return (int *)SendMessageA(hWnd, 2u, 0, 0);
    }
  }
  return result;
}

从遍历完全的e4f8b4和开始的e49194作差,除以单位长度可以得知一共是50个单位

很明显flag的值不全是可见字符,说明在别的地方还有解密操作,通过交叉引用可以找到
在这里:
[C++] 纯文本查看 复制代码
int __thiscall hit(void *this)
{
  int result; // eax@1
  int v2; // ecx@2
  int v3; // edx@2

  result = sub_E43440(this);//得到被击中的怪物指针
  if ( result != -1 )
  {
    v2 = 132 * result;
    v3 = dword_E49190[132 * result];//该怪物的血量,OD中查到是100
    if ( v3 > 0 )
    {
      dword_E49190[v2] = v3 - 2;//每单位时间hp-2,实际上一枪经过了10单位时间(枪声间隔),即一枪是20hp
    }
    else
    {
      dword_E49194[v2] = 0;
      flag[result] ^= byte_E49184[v2 * 4];//flag的第n个字节与第n个怪物对象的某个数据进行异或
    }
  }
  return result;
}


乍一看不一定能识别出来这个函数是做什么的(没有注释的话啦
但是查看交叉引用就能发现这个函数是在下述过程中被调用的:

[C++] 纯文本查看 复制代码
if ( dword_E47BD4 )
          {
            hit(v12);
            if ( dword_E47BD8 < 5 )//也许是后坐力导致的镜头偏移?但是从游戏观察来看镜头上抬是和音效同步的,即一次枪声上抬一次;不明白这里的gap的作用
              sub_E41880((int)&flt_E47BE0, dword_E47D70, (int)&v21);
            else
              dword_E47BD8 = 0;
            ++dword_E47BD8;
            if ( shoot_gap >= 10 )              // 每10单位时间播放一次音效
            {
              shoot_gap = 0;
              PlaySoundA("data\\Shoot.wav", 0, 1u);
            }
            ++shoot_gap;
          }

很明显,是射击函数
由此可以推断hit函数中进行的是运算等逻辑部分

我直接用IDC打印了一下对象的值,发现是空的;
说明还有动态申请的过程
在IDA中直接运行游戏,然后IDC脚本打印:
[C++] 纯文本查看 复制代码
IDC>auto i;for(i=0;i<50;i++)Message(“%d “, Byte(0xe49184 + i*132*4)); 
0 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128 132 136 140 144 148 152 156 160 164 168 172 176 180 184 188 192 196


还好,就是i*4,很好处理
直接python脚本跑一下就能得到:
先Dump字符串的ASCII值


[C++] 纯文本查看 复制代码
IDC>auto i;for(i=0;i<50;i++)Message(“%d, “, Byte(0xe47028 + i)); 
67, 107, 102, 107, 98, 117, 108, 105, 76, 69, 92, 69, 95, 90, 70, 28, 7, 37, 37, 41, 112, 23, 52, 57, 1, 22, 73, 76, 32, 21, 11, 15, 247, 235, 250, 232, 176, 253, 235, 188, 244, 204, 218, 159, 245, 240, 232, 206, 240, 169,


然后脚本处理
[Python] 纯文本查看 复制代码
s = [67, 107, 102, 107, 98, 117, 108, 105, 76, 69, 92, 69, 95, 90, 70, 28, 7, 37, 37, 41, 112, 23, 52, 57, 1, 22, 73, 76, 32, 21, 11, 15, 247, 235, 250, 232, 176, 253, 235, 188, 244, 204, 218, 159, 245, 240, 232, 206, 240, 169]
for i in range(50):
    print(chr(s[i] ^ i*4), end='')


Congratulation~ Game Clear! Password is Thr3EDPr0m

这题中i*4的值是很简单的,如果很困难怎么办呢?
其实还可以写外挂,增伤锁血之类的
将hit函数中的hp-2改为-100(实践来看,远距离的散射效果似乎是按照每单位时间进行的,也就是说如果离得远很有可能一枪的1/10没打中啥的……奇妙的判定)

这样可以快速将怪打完,剩最后一只了合影留个念

但是最后clear了也没弹窗,再检查一下内存:
[C++] 纯文本查看 复制代码
IDC>auto i;for(i=0;i<50;i++)Message(“%d “, Byte(0xe49194 + i*132*4)); 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1

最后有2个单位还没死……想了一下,应该一个是中间那个大圆球,一个是自己吧
自杀理论上来说跟最后一只怪倒是说不定有可能;但是中间那个大圆球被命中的时候不会触发hit的击中判定(下断未触发),所以也就不会被扣血量,更不可能杀死……╮(╯_╰)╭没辙,正常游玩下是不可能得到flag的
有点好奇会不会有人五枪一只、慢慢打死48只怪兽,然后发现啥都没有呢……太恶意了OTZ

整体来说,逆向C++的类只能算初入门,还欠缺很多中间很多函数仍然不明所以,虽然找到flag了但是对整个程序的把握还差得远……
(IDA的动态调试真难用,但是ODDump内存更不方便啊QAQ)
PS:由于Data+DX的大小堪堪超过了1MB,只得分成两个包╮(╯_╰)╭PPS:其实可以直接去reversing.kr网站上下载的呀……_(:з」∠)_

Direct3D_FPS.rar

754.77 KB, 下载次数: 23, 下载积分: 吾爱币 -1 CB

data.rar

360.92 KB, 下载次数: 5, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 5吾爱币 +10 热心值 +5 收起 理由
WYWZ + 1 + 1 谢谢@Thanks!
2864095098 + 1 + 1 热心回复!
lies2014 + 1 + 1 用心讨论,共获提升!
qwerttqqaz + 1 + 1 我很赞同!
Sound + 6 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

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

gunxsword 发表于 2017-9-29 13:09
最终有没有得到可以提交AUTH的FLAG啊
linuxprobe 发表于 2017-9-28 20:20
Sound 发表于 2017-9-28 20:31
wls 发表于 2017-9-28 20:53
不错,非常好
 楼主| whklhh 发表于 2017-9-28 21:45
Sound 发表于 2017-9-28 20:31
加油 我希望在rank榜单上 看到 你留下www.52pojie.cn 的大名

任重而道远啊 我会加油的~谢谢版主大大支持~
2864095098 发表于 2017-9-29 01:14
算法,学习了
c0d1 发表于 2017-11-13 18:33
您的解密时候的python脚本有一个小问题,是否是写漏了print(chr(s[i]^i*4),end=''),s是一个list...如果按您这样写的话会报错的
 楼主| whklhh 发表于 2017-11-14 15:12
本帖最后由 whklhh 于 2017-11-14 15:15 编辑
c0d1 发表于 2017-11-13 18:33
您的解密时候的python脚本有一个小问题,是否是写漏了print(chr(s^i*4),end=''),s是一个list...如果按您这 ...

这个貌似是论坛编辑器的问题,有时候会吃掉【i】 遇到过很多次了 后来想起来的时候会把i换成j来规避,有时候忘了就~嘿嘿~
谢谢指出~
宗泽666 发表于 2019-8-6 12:22
怎么在IDA中直接运行游戏?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-12-29 16:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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