170928 逆向-Reversing.kr(Direct3D_FPS)
来源:互联网 发布:禄宏微交易 知乎 编辑:程序博客网 时间:2024/06/01 23:57
1625-5 王子昂 总结《2017年9月28日》 【连续第361天总结】
A. Reversing.kr-Direct3D_FPS
B.
这次DX让我有点怂……
一直对这种大型程序都心有畏惧,可能是因为没写过不了解其原理吧
解压出来可以看到包含一个DX库,一个Data文件夹下放置着各种图片和音效资源,一个exe
运行一打开就把我吓了一跳,差点以为不小心打开的恐怖游戏……
这囧囧的怪物,还有后面那张好像兵库北的微笑的图片(:з」∠)
惯例拖入IDA查找字符串,这次核心函数就在WinMain中
由于函数太长就不放全部内容了
大体上可以根据游戏画面中左下角显示的10和失败提示找到HP
根据枪声音效找到射击控制部分
根据按键的Switch结构找到移动部分
另外射击的后坐力和音效是有一定的间隔的,这意味着一定有一个计时器(否则将会不间断的连续产生枪声音效,很违和)
试玩了一下,很简陋不过五脏俱全了,基本上开5枪才能杀死一个怪;另外随着距离增加还有随机的散射效果
基本理清整个程序的结构,怪物和自己应该都是对象,在内存中各占132个字节
不过没分析清楚类的成员;只能看出来有存活标识和HP两部分
沿着GameClear!的字符串可以找到胜利检查函数:
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的值不全是可见字符,说明在别的地方还有解密操作,通过交叉引用可以找到
在这里:
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;}
乍一看不一定能识别出来这个函数是做什么的(没有注释的话啦
但是查看交叉引用就能发现这个函数是在下述过程中被调用的:
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脚本打印:
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值
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,
然后脚本处理
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了也没弹窗,再检查一下内存:
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++的类只能算初入门,还欠缺很多……
(IDA的动态调试真难用,但是ODDump内存更不方便啊QAQ)
C. 明日计划
算法学习
Reversing.kr
- 170928 逆向-Reversing.kr(Direct3D_FPS)
- 170923 逆向-Reversing.kr(MusicPlayer)
- 170925 逆向-Reversing.kr(Replace)
- 170926 逆向-Reversing.kr(ImagePrc)
- 170927 逆向-Reversing.kr(Position)
- 170929 逆向-Reversing.kr(Ransomware)
- 170930 逆向-Reversing.kr(Twist)
- 171001 逆向-Reversing.kr(WindowsKernel)
- 171002 逆向-Reversing.kr(AutoHotKey)
- 171003 逆向-Reversing.kr(CSHOP)
- 171010 逆向-Reversing.kr(PEPassword)
- 171011 逆向-Reversing.kr(HateIntel)
- 171013 逆向-Reversing.kr(AutoHotKey2)
- 171014 逆向-Reversing.kr(x64 Lotto)
- 171017 逆向-Reversing.kr(CSharp)
- 171018 逆向-Reversing.kr(Flash Encrypt)
- 171019 逆向-Reversing.kr(MetroApp)
- 171020 逆向-Reversing.kr(Multiplicative)
- tensorflow中nn的padding
- response.setContentType()与response.setCharacterEncoding()
- HASH+平衡树 [JSOI2008]火星人prefix
- 找第K小的数(O(N))(运用随机思想)
- [LeetCode-Algorithms-25] "Reverse Nodes in k-Group" (2017.9.28-WEEK4)
- 170928 逆向-Reversing.kr(Direct3D_FPS)
- Dynamic Programming:198. House Robber
- python简介
- luogu1967 货车运输
- PAT——1023组个最小数
- 在使用myeclipse10 新手上路学习hibernate 时产生如下错误org.hibernate.InvalidMappingException: Unable to read XML at
- jQuery根据name属性操作textarea、text、radio,通达OA表单js设计
- 智力题2
- 用canvas将qrcode生成的二维码与背景图片合成可以一起发送识别