menu 牢记自己是菜
XCTF八月月赛--WMCTF2020 RE Wmware
4787 浏览 | 2020-08-03 | 阅读时间: 约 9 分钟 | 分类: XCTF比赛 | 标签:
请注意,本文编写于 1352 天前,最后修改于 1350 天前,其中某些信息可能已经过时。

0x1 前言

首先庆祝一下,自己终于在XCTF比赛中,拿到了自己的第一个题目的分。有一说一这个题目除了样子比较新奇之外,其余的大多都是基本功,没错一个二进制选手的基本功(包括汇编,调试,数学等)。整道题目从8.1下午4点开始一直到8.2晚上9点半,除去吃饭睡觉,历时将近24个小时。并且由于大多数的逻辑,内存我都是采用手操的方式,导致速度下降(脚本编程能力需要提高)。所以本篇博客将分为四段,阐述我自己的做题思路。
前排警告:本博客只是记录做题过程,为各位师傅提供一个笨比的解法。
文章可能会涉及:

  1. 人工计算机模拟内存
  2. 笨比的python脚本
  3. 手工还原flag
    等令人不适的做法,请在做好心理准备后,酌情观看。前言的最后,附上世界名画,手工管理的内存。


0x2 文件的初步分析

0x2a 环境的安装

首先我们拿到题目,好家伙,这是个啥玩意。一堆让人无法理解的东西,点开txt,好像是一个计算机的配置,具体的细节也是完全看不懂的。看看题目的提示,题目的名字一点用都没有,就告诉你这是个软件。但是后面的./bochs -q就很关键,这很像是一个命令行。首先我们搜索一下bochs,发现这好像是个开源的虚拟机。这是大概就明白之前的的那堆文件是干啥的了,应该是一个虚拟机的配置文件,里面规定了内存等一系列的东西。
bochsrc.txt
在下载bochs的时候,一个逆向手一定会干的一件事情就是将他放到IDA里面看看。哦哟,我的老天爷,连七八糟的,就是一个大的虚拟机,函数乱七八糟的,并且伴随着大量没法反汇编的数据,这要是分析起来肯定要命(后面证明IDA确实没咋用到)。还有一个有意思的事情就是,我在逛bochs贴吧的时候,发现这个软件好像可以装在手机上,在手机上模拟PC环境。
在下载完成后我们进入,下载的根目录。我装的windows版的,因为我觉得在虚拟机里装虚拟机我可能会被卡死。

我们主要用的是用dbg文件对题目所给出的虚拟机进行调试。如何打开虚拟机?

bochsdbg.exe -f bochsrc.txt

这里不得不说,出题人并没有为难我们,配置文件的路径都是事先写好的,并且将需要用的环境(包括键盘等一些列资源)都统一的放在了.src下,直接使用虚拟机加载从给出的配置文件,就可以启动程序。不要看就是一行代码,我可是研究了好久,试了很多种情况的。还自己从头学着用bochs搭建了一个虚拟机,整个体验就是难用,VM真香。
PS:其实仔细看所给出的文件,在.src中,除了开辟的存储空间之外的的文件,你下载的bochs里面都有一模一样的文件只不过是放在不同的地方的。有点小贴心。

0x2b 调试器的使用

cmd输入指令,运行。开始界面直接点start就行了(程序看起来有点像微机接口实验的感觉)。这理就要稍微说一下bochsdbg的使用方法了。详情参见这里
这里主要说明几个我用的比较多的指令:

  • c|cont 向下执行,相当于WinDBG的“g”
  • s|step|stepi [count] 单步执行,相当于WinDBG的“t”,count 默认为 1
  • blist 显示断点状态,相当于WinDBG的“bl”
  • n 步过,遇见函数直接跳过
  • b 0xFFFFF 在地址下断点
  • d|del|delete [num] 删除断点
  • trace-reg on 每执行一条指令就打印CPU信息,主要就是寄存器
  • u|disas|disassemble [/num] [start] [end]反汇编物理地址start到end 之间的代码。

果不指定参数则反汇编当前EIP指向的代码。
整个调试程序与GDB很像(PWN的工具),我主要只用到了这些操作,至于为什仫不显示内存的原因是因为我微机学的太差啦,完全搞不清楚内存在哪里,按照调试打印出来的内存总是对不上。所以我最后采取了手动记录内存的方式。
然后再说一下整个调试器的构成:这也是摸了好久才摸出来的

0x3 代码的初步分析

好了现在我已经完全掌握调试了(压根不懂),我们要开始对程序开始分析了。首先回忆一下,OD里面我们怎么调试程序的,那一定是菜鸡三连:打开中文搜索,找到关键字符,下断运行。好的在这里面,我们啥也干不了,没有搜索,看不见字符。那我们就用最原始的方法找代码吧,启动程序next到底。碰见程序跑飞,记录跑飞位置,再次下断点,使用命令s步入。根据经验(运气),在输入前的循环大多数都是程序机器的初始化,和一些垃圾循环。想办法找到跳出点,断点跳出。不要怕断点打错或者其他什么问题。因为程序不会坏,可以再次加载。经过努力我们成功的。。。。。成功的执行到了硬件代码,为啥是硬件代码呢。来大佬们看这个。

首先感谢鼎哥的调试素材。你看这个代码,想不想咱们微机原理接口键盘实验的输入。从一个端口输入,每次检测是否有输入,然后判断是否跳出。那然后咋办,按照我们的断点一步步退回去。终于在0x6114处找到了我们想要的东西。

哈?你问我为啥代码这么整齐,那一定是用了指令u返汇编的代码,然后粘贴到了txt中,方便下次查看。好此我们已经找到了核心判断了,向上翻翻,判断函数,基本断定这里应该是主代码段了。将这段代码扣下来,就是我们需要分析的代码了。

00006000: (                    ): jmp .+0                   ; eb00
00006002: (                    ): xor ecx, ecx              ; 31c9
00006004: (                    ): cmp ecx, 0x00000081       ; 81f981000000
0000600a: (                    ): jz .+226                  ; 0f84e2000000
00006010: (                    ): xor esi, esi              ; 31f6
00006012: (                    ): cmp esi, 0x00000009       ; 83fe09
00006015: (                    ): jz .+209                  ; 0f84d1000000
0000601b: (                    ): xor edx, edx              ; 31d2
0000601d: (                    ): mov eax, esi              ; 89f0
0000601f: (                    ): inc eax                   ; 40
00006020: (                    ): mov ebx, 0x00000009       ; bb09000000
00006025: (                    ): div eax, ebx              ; f7f3
00006027: (                    ): mov edi, edx              ; 89d7
00006029: (                    ): xor edx, edx              ; 31d2
0000602b: (                    ): mov eax, ecx              ; 89c8
0000602d: (                    ): mov ebx, 0x00000003       ; bb03000000
00006032: (                    ): div eax, ebx              ; f7f3
00006034: (                    ): jz .+5                    ; 7405
00006036: (                    ): jnz .+3                   ; 7503
00006038: (                    ): ret 0x0099                ; c29900
0000603b: (                    ): cmp edx, 0x00000000       ; 83fa00
0000603e: (                    ): jz .+7                    ; 7407
00006040: (                    ): cmp edx, 0x00000001       ; 83fa01
00006043: (                    ): jz .+56                   ; 7438
00006045: (                    ): jnz .+108                 ; 756c
00006047: (                    ): shl esi, 0x02             ; c1e602
0000604a: (                    ): mov eax, dword ptr ds:[esi] ; 3e8b06
0000604d: (                    ): shl edi, 0x02             ; c1e702
00006050: (                    ): mov ebx, dword ptr ds:[edi] ; 3e8b1f
00006053: (                    ): mov edx, eax              ; 89c2
00006055: (                    ): mov edi, ebx              ; 89df
00006057: (                    ): or eax, ebx               ; 09d8
00006059: (                    ): not edx                   ; f7d2
0000605b: (                    ): not edi                   ; f7d7
0000605d: (                    ): or edx, edi               ; 09fa
0000605f: (                    ): and eax, edx              ; 21d0
00006061: (                    ): mov edx, eax              ; 89c2
00006063: (                    ): mov ebx, 0x24114514       ; bb14451124
00006068: (                    ): mov edi, ebx              ; 89df
0000606a: (                    ): not eax                   ; f7d0
0000606c: (                    ): not ebx                   ; f7d3
0000606e: (                    ): and eax, ebx              ; 21d8
00006070: (                    ): not eax                   ; f7d0
00006072: (                    ): and edx, edi              ; 21fa
00006074: (                    ): not edx                   ; f7d2
00006076: (                    ): and eax, edx              ; 21d0
00006078: (                    ): mov dword ptr ds:[esi], eax ; 3e8906
0000607b: (                    ): jmp .+102                 ; eb66
0000607d: (                    ): shl esi, 0x02             ; c1e602
00006080: (                    ): mov eax, dword ptr ds:[esi] ; 3e8b06
00006083: (                    ): shl edi, 0x02             ; c1e702
00006086: (                    ): mov ebx, dword ptr ds:[edi] ; 3e8b1f
00006089: (                    ): mov edx, eax              ; 89c2
0000608b: (                    ): mov edi, ebx              ; 89df
0000608d: (                    ): not eax                   ; f7d0
0000608f: (                    ): not ebx                   ; f7d3
00006091: (                    ): and eax, ebx              ; 21d8
00006093: (                    ): not eax                   ; f7d0
00006095: (                    ): and edx, edi              ; 21fa
00006097: (                    ): not edx                   ; f7d2
00006099: (                    ): and eax, edx              ; 21d0
0000609b: (                    ): mov edx, eax              ; 89c2
0000609d: (                    ): mov ebx, 0x01919810       ; bb10989101
000060a2: (                    ): mov edi, ebx              ; 89df
000060a4: (                    ): not ebx                   ; f7d3
000060a6: (                    ): and eax, ebx              ; 21d8
000060a8: (                    ): not edx                   ; f7d2
000060aa: (                    ): and edx, edi              ; 21fa
000060ac: (                    ): or eax, edx               ; 09d0
000060ae: (                    ): mov dword ptr ds:[esi], eax ; 3e8906
000060b1: (                    ): jmp .+48                  ; eb30
000060b3: (                    ): shl esi, 0x02             ; c1e602
000060b6: (                    ): mov eax, dword ptr ds:[esi] ; 3e8b06
000060b9: (                    ): shl edi, 0x02             ; c1e702
000060bc: (                    ): mov ebx, dword ptr ds:[edi] ; 3e8b1f
000060bf: (                    ): mov edx, eax              ; 89c2
000060c1: (                    ): mov edi, ebx              ; 89df
000060c3: (                    ): not ebx                   ; f7d3
000060c5: (                    ): and eax, ebx              ; 21d8
000060c7: (                    ): not edx                   ; f7d2
000060c9: (                    ): and edx, edi              ; 21fa
000060cb: (                    ): or eax, edx               ; 09d0
000060cd: (                    ): mov edx, eax              ; 89c2
000060cf: (                    ): mov ebx, 0x19260817       ; bb17082619
000060d4: (                    ): mov edi, ebx              ; 89df
000060d6: (                    ): or eax, ebx               ; 09d8
000060d8: (                    ): not edx                   ; f7d2
000060da: (                    ): not edi                   ; f7d7
000060dc: (                    ): or edx, edi               ; 09fa
000060de: (                    ): and eax, edx              ; 21d0
000060e0: (                    ): mov dword ptr ds:[esi], eax ; 3e8906
000060e3: (                    ): shr esi, 0x02             ; c1ee02
000060e6: (                    ): inc esi                   ; 46
000060e7: (                    ): jmp .-218                 ; e926ffffff
000060ec: (                    ): inc ecx                   ; 41
000060ed: (                    ): jmp .-238                 ; e912ffffff
000060f2: (                    ): xor ecx, ecx              ; 31c9
000060f4: (                    ): xor edx, edx              ; 31d2


000060f6: (                    ): cmp ecx, 0x00000012       ; 83f912
000060f9: (                    ): jz .+25                   ; 7419
000060fb: (                    ): shl ecx, 1                ; d1e1
000060fd: (                    ): mov ax, word ptr ds:[ecx-19092685] ; 3e668b8133abdcfe
00006105: (                    ): mov bx, word ptr ds:[ecx] ; 3e668b19
00006109: (                    ): cmp ax, bx                ; 6639d8
0000610c: (                    ): jz .+1                    ; 7401
0000610e: (                    ): inc edx                   ; 42
0000610f: (                    ): shr ecx, 1                ; d1e9
00006111: (                    ): inc ecx                   ; 41
00006112: (                    ): jmp .-30                  ; ebe2



00006114: (                    ): cmp edx, 0x00000000       ; 83fa00
00006117: (                    ): jnz .+98                  ; 7562
00006119: (                    ): mov byte ptr gs:0x00000320, 0x41 ; 65c6052003000041
00006121: (                    ): mov byte ptr gs:0x00000321, 0x02 ; 65c6052103000002
00006129: (                    ): mov byte ptr gs:0x00000322, 0x63 ; 65c6052203000063
00006131: (                    ): mov byte ptr gs:0x00000323, 0x02 ; 65c6052303000002
00006139: (                    ): mov byte ptr gs:0x00000324, 0x63 ; 65c6052403000063
00006141: (                    ): mov byte ptr gs:0x00000325, 0x02 ; 65c6052503000002
00006149: (                    ): mov byte ptr gs:0x00000326, 0x65 ; 65c6052603000065
00006151: (                    ): mov byte ptr gs:0x00000327, 0x02 ; 65c6052703000002
00006159: (                    ): mov byte ptr gs:0x00000328, 0x73 ; 65c6052803000073
00006161: (                    ): mov byte ptr gs:0x00000329, 0x02 ; 65c6052903000002
00006169: (                    ): mov byte ptr gs:0x0000032a, 0x73 ; 65c6052a03000073
00006171: (                    ): mov byte ptr gs:0x0000032b, 0x02 ; 65c6052b03000002
00006179: (                    ): jmp .+64                  ; eb40
0000617b: (                    ): mov byte ptr gs:0x00000320, 0x46 ; 65c6052003000046
00006183: (                    ): mov byte ptr gs:0x00000321, 0x04 ; 65c6052103000004
0000618b: (                    ): mov byte ptr gs:0x00000322, 0x61 ; 65c6052203000061
00006193: (                    ): mov byte ptr gs:0x00000323, 0x04 ; 65c6052303000004
0000619b: (                    ): mov byte ptr gs:0x00000324, 0x69 ; 65c6052403000069
000061a3: (                    ): mov byte ptr gs:0x00000325, 0x04 ; 65c6052503000004
000061ab: (                    ): mov byte ptr gs:0x00000326, 0x6c ; 65c605260300006c
000061b3: (                    ): mov byte ptr gs:0x00000327, 0x04 ; 65c6052703000004
000061bb: (                    ): jmp .-2                   ; ebfe
000061bd: (                    ): add byte ptr ds:[eax], al ; 0000
000061bf: (                    ): add byte ptr ds:[eax], al ; 0000
000061c1: (                    ): add byte ptr ds:[eax], al ; 0000
000061c3: (                    ): add byte ptr ds:[eax], al ; 0000
000061c5: (                    ): add byte ptr ds:[eax], al ; 0000
000061c7: (                    ): add byte ptr ds:[eax], al ; 0000
000061c9: (                    ): add byte ptr ds:[eax], al ; 0000
000061cb: (                    ): add byte ptr ds:[eax], al ; 0000
000061cd: (                    ): add byte ptr ds:[eax], al ; 0000
000061cf: (                    ): add byte ptr ds:[eax], al ; 0000
000061d1: (                    ): add byte ptr ds:[eax], al ; 0000
000061d3: (                    ): add byte ptr ds:[eax], al ; 0000
000061d5: (                    ): add byte ptr ds:[eax], al ; 0000
000061d7: (                    ): add byte ptr ds:[eax], al ; 0000
000061d9: (                    ): add byte ptr ds:[eax], al ; 0000
000061db: (                    ): add byte ptr ds:[eax], al ; 0000
000061dd: (                    ): add byte ptr ds:[eax], al ; 0000

0x4 代码的输入与核心逻辑分析

0x4a 输入分析

ps:这一部分已经是8.2 号了,没错上面看起来简单的部分我分析了快12个小时,直到晚上的3点多。后面的部分是8.2号早上九点后的结果。
哇!你说这代码长吗,好像挺长的。但是若果放在OD里面分析,那一定一点问题都没有。毕竟OD功能太强大了,帮你追内存,划堆栈,告诉你哪个里面现在是啥状态,就差给你把flag找到了。但是这里面由于用的不是很熟(或者说没有),我不知道该从什么样子的地址开始查看内存,栈内也只有十六进制数,大多情况下也没什么帮助。所以这个汇编还是蛮痛苦的。
我们先来看看判断函数,我们要知道这个判断函数在干嘛。

000060f6: (                    ): cmp ecx, 0x00000012       ; 83f912   #这里0x12,循环18次比较
000060f9: (                    ): jz .+25                   ; 7419
000060fb: (                    ): shl ecx, 1                ; d1e1
000060fd: (                    ): mov ax, word ptr ds:[ecx-19092685] ; 3e668b8133abdcfe
00006105: (                    ): mov bx, word ptr ds:[ecx] ; 3e668b19
00006109: (                    ): cmp ax, bx                ; 6639d8
0000610c: (                    ): jz .+1                    ; 7401
0000610e: (                    ): inc edx                   ; 42
0000610f: (                    ): shr ecx, 1                ; d1e9
00006111: (                    ): inc ecx                   ; 41
00006112: (                    ): jmp .-30                  ; ebe2
00006114: (                    ): cmp edx, 0x00000000       ; 83fa00
00006117: (                    ): jnz .+98                  ; 7562

这里的逻辑大概就是比较18次,现将两块指定内存中的数据放入ax和bx注意是16位寄存器,为啥要注意这里,之后会提到。然后进行比较,假若不相等就将edx自加1,最后如果edx为0的话,那么就算校验成功。这里还是满人性化的,对于我这种不会看内存的人来说,它可以保证在你运行一次之后,看完所有的内存校验数据,而不会因为一位的错误而被中断。后面分析完算法,你会发现,这玩意只要错一位,整个校验数据基本上都是错的,而且是一点都不沾边的那种。
既然数据是被从内存中取出来的,那么一定有写入的过程,就算校验数据没有,但是加密数据一定有。于是在上面分析算法的时候,我们要注意内存的读写。
边调试边看代码,你会在代码中发现三处相同的地方,就是:

0000604a: (                    ): mov eax, dword ptr ds:[esi] ; 3e8b06
0000604d: (                    ): shl edi, 0x02             ; c1e702
00006050: (                    ): mov ebx, dword ptr ds:[edi] ; 3e8b1f
00006053: (                    ): mov edx, eax              ; 89c2

这样的代码将数据写入寄存器,然后进行计算。于是我们在0x604a处下断点,观察是否能看见我们的输入。
我在程序中输入了很多小a大概有四五行吧。执行代码,寄存器中出现了整齐的0x73.

至于为啥是0x73,你多试几次其他的字符就好了,你会发现这是这个程序对我们键盘的译码。打个比方,你现在低头看自己的键盘,a:0x73,s:0x74,d:0x75依次类推。注意编码大小写敏感。
但当我们输入的是不同的字符的,栈内却不是我们想要的结果。
我为了得到整个键盘的字典我构造了如下flag:MWCTF{123456789asdfghjklqwzxcvbnmer}一共36位,为啥是36位,后面再说。
寄存器中的数据:

看见这个,相必做过子洋师傅出的那道题,应该瞬间就你能明白吧。他将输入的数据根据一个数组(也可能是个循环,因为在我构建字典的时候,发现之间还是有一定规律的)完成打乱,再存入内存。这里就直接上图吧,当当当当(记得有音调),我的人工内存。
这个是输入flag的位数,编码和字符的字典:
字典一
这个是被打乱后的字典,上面构造一次是:顺序,编码,翻译的字符,最下面两行对应在原字典中的顺序。
字典2
该大家一个清楚的数组吧:

add[19,13,7,1,8,2,31,25,32,26,20,14,21,15,9,3,10,4,33,27,34,28,22,16,23,17,11,5,12,6,35,29,36,30,24,18]

至此我们输入就分析完毕了,下面就是加密代码的分析了。

0x4 代码的输入与核心逻辑分析

前排提示:测试flag依旧是MWCTF{123456789asdfghjklqwzxcvbnmer}
代码逻辑还是蛮轻松的,就是有点麻烦。这里我就叨叨我获得代码的过程了,直接说逻辑吧。有点不好说,我尽力而为吧。
首先整个加密逻辑是一个两层的循环,最外层是一个大循环一共循环43次(0x81/3),这个循环控制了三个小循环,每个小循环循环九次。
每个小循环中都是由not or and 三种运算这令构成的,用来对数据进行加密。每次循环都会从内存中取值,分别放入eax与ebx中。ebx总是取到eax后面的数据。每次函数生成一个新的8位数据,将其存在原有数据后面,等待下次被使用。
由于只有第一个循环用到了输入,并且在第一个循环的最后一次,已经使用到了第一次生成的数据,所以flag是36位的(9*8/2)
以上所有的都是一点一点调试出来的,就光抄每步寄存器里的关键值就抄了好几页。
这个是第一轮大循环中除去前九个输入后,生成的数据。

这里举个例子:
原始输入:1,2,3,4,5,6,7,8,9
第一层循环使用1,2进行加密,生成10
第一次结束内存:1,2,3,4,5,6,7,8,9,10
第二次使用:2,3,生成11
第二次结束内存:1,2,3,4,5,6,7,8,9,10,11
依次类推。
至于里面的算法很简单,基本上边跟边把它翻译成脚本,之后直接运行,将输入输出与程序进行对比,确保无误就可以了。来上我的垃圾脚本,未修改。把子洋师傅差点搞吐了233333。

import re
def first(A,B):
    #A=0xc9f5f409
    #B=0xe531241e
    C=A | B
    #print(hex(C))
    C2=~A+0xffffffff+1
    B2=~B+0xffffffff+1
    #print(hex(C2))
    #print(hex(B2))
    D=C2 | B2
    #print(hex(D))
    H=C&D#下一个常数的参
    #print(hex(H))

    DATA=0x24114514
    E=~H+0xffffffff+1
    R=~DATA+0xffffffff+1
    SS=E&R
    NSS=~SS+0xffffffff+1
    SSS=H&DATA
    NSSS=~SSS+0xffffffff+1
    last=NSSS&NSS
    #print(hex(last))
    return last

def sencond(Q,W):
    #Q=0xfac0b72f
    #W=0xda286bf9
    NQ=~Q+0xffffffff+1
    NW=~W+0xffffffff+1
    P=NQ&NW
    NP=~P+0xffffffff+1
    L=Q&W
    NL=~L+0xffffffff+1
    last1=NL&NP
    #print(hex(last1))

    DATA2=0x01919810
    NDATA2=~DATA2+0xffffffff+1
    K=last1&NDATA2
    Nlast1=~last1+0xffffffff+1
    J=Nlast1&DATA2
    last2=J|K
    #print(hex(last2))
    return last2

def thrid(T,Y):
    #T=0xf1aab8d8
    #Y=0x217944c6
    NY=~Y+0xffffffff+1
    V=T&NY
    NT=~T+0xffffffff+1
    V2=NT&Y
    last3=V|V2
    #print(hex(last3))

    DATA3=0x19260817
    LLL=last3|DATA3
    Nlast3=~last3+0xffffffff+1
    NDATA3=~DATA3+0xffffffff+1
    #print(hex(Nlast3))
    LLLL=Nlast3|NDATA3
    last4=LLL&LLLL
    #print(hex(last4))
    return last4

if __name__ == '__main__':
    add=[0x765d5796,0x58b78565,0x8666775e,0x785f59b3,0x5a998781,0x67827973,0x7a745ba6,0x5c6f6883,0x70847b75]
    i=0
    j=1
    for m in range(0,43):
        for Q in range(0,9):
            add=add+[first(add[i],add[j])]
            i=i+1
            j=j+1
        for Q in range(0,9):
            add=add+[sencond(add[i],add[j])]
            i=i+1
            j=j+1
        for Q in range(0,9):
            add=add+[thrid(add[i],add[j])]
            i=i+1
            j=j+1
    UU=1
    for U in add:
        print(hex(U))

其实我觉得直接看汇编,可能比我这个破脚本好理解一点。
对一下最后的校验数据:

这里我将8位全抄下来了,但是只用后四位。
对比我们手动生成的内存,发现就是最后九个数据。

0xe27157c9
0x7d312880
0x1c487924
0x5ff7f6b2
0x215387d6
0x4201d467
0x748b4f3
0x6eeac791
0x7d375861

至此,我们程序的逻辑也完全清楚了,现在就只剩下反向解密了。

0x5 我数学不好

啊!这个是子洋师傅给我说的,然后用了3分钟就帮我化简了加密函数∠( ᐛ 」∠)_。化简之后的加密函数只是三个异或。

这个来自于QQ聊天记录,在此感谢子洋,摸摸大。什么你问我有多感谢,来看一张我的化简图吧!

而且还不知道对不对。
好了我们写出反向脚本,将所给的九位为数据,逆向返还内存。

def FA3(A,B):
    DATA3=0x19260817
    return A^B^DATA3

def FA2(C,D):
    DATA2=0x01919810
    return C^D^DATA2

def FA1(E,F):
    DATA=0x24114514
    return E^F^DATA

if __name__ == '__main__':
    add=[0x4537a864,0x71d63591,0x18a955e7,0x6ae00499,0xeda06c28,0x8105055f,0x02ba6d11,0x421a04b5,0xec5574d8]
    i=0
    j=8
    for m in range(0,43):
        for Q in range(0,9):
            add=add+[FA3(add[i],add[j])]
            i=i+1
            j=j+1
        for Q in range(0,9):
            add=add+[FA2(add[i],add[j])]
            i=i+1
            j=j+1
        for Q in range(0,9):
            add=add+[FA1(add[i],add[j])]
            i=i+1
            j=j+1
    for U in add:
        print(hex(U))

将最后的九位排列好,人肉计算机启动,手动还原。

0x6 后记

在复现的时候,我有了一个想法,既然找到了主干代码,并且也有二进制流,是不是可以尝试将他们搞出来,使用IDA反编译,在F5呢。不晓得呢,应该也是种方法,不出意外的话。噶有!下次继续努力吧!

发表评论

email
web

全部评论 (共 4 条评论)

    2020-08-05 11:10
    ヾ(≧∇≦*)ゝ
    2020-08-05 01:51
    炜昊tql,动调的过程工作量好大呀,我成功被劝退
    Ld1ng
    2020-08-05 00:05
    太强了我的炜神!
      2020-08-05 11:10
      @Ld1ng(☆ω☆)