Rervese.kr题解 Assassin菜逼之路

Easy Crack

很久不做题了,就当是练手了,很简单的题目,首先查看字符串看到

这里写图片描述

关键词很少了,很明确,然后再看一下判断条件貌似就一个
这里写图片描述

很容易就可以组合最终结果是

Ea5yR3versing

Easy Keygen

运行一下程序,发现需要输入一个Name然后输入一个什么注册码,要求Name输入和注册码对应,注册码要求是5B134977135E7D13,估计是一个简单的算法吧。
进入一看发现就是个简单的抑或…

这里写图片描述

简单写一个小程序

# -*- coding: utf-8 -*-  
import pymssql
target = [0x5b,0x13,0x49,0x77,0x13,0x5e,0x7d,0x13]
#target = '5B134977135E7D13'
flag = ''
for i in range(len(target)):
    if i%3==0:
        flag += chr(target[i]^16)
    elif i%3==1:
        flag += chr(target[i]^32)
    elif i%3==2:
        flag += chr(target[i]^48)
print flag

得到答案是K3yg3nm3

Easy Unpack

下载文件之后查看ReadME发现需要找到入口地址OEP,说实话之前都没怎么接触过脱壳的内容,在网上照葫芦画瓢试了试,显示简单所谓的不分析的单步跟踪法,具体的思路如下:

  1、用OD载入待脱壳文件,如果出现压缩提示,选择“不分析代码”;
  2、向下单步跟踪,实现向下的跳转;
  3、遇到程序往上跳转的时候(包括循环),在回跳的下一句代码上单击并按键盘上的“F4”键跳过回跳指令;
  4、OD中的灰色线条表示跳转没有实理,不必理会,红色线条表示跳转已经实现;
  5、如果刚载入程序的时候,在附近有一个CALL指令,那么就要按键盘上的“F7”键跟进这个CALL内,不然程序很容易运行起来(这个在这里貌似没什么体现);
  6、在跟踪的时候,如果执行某个CALL指令后就运行,一定要按键盘上的“F7”键进入这个CALL之内再单步跟踪(这个也没什么体现,我直接都是F8搞定的);
  7、遇到在popad指令下的远转移指令时,要格处注意,因为这个远转移指令的目的地很可能就是OEP。

跟着上面的步骤,主要就是F8和F4一会儿就有一个长距离条转

这里写图片描述

之后就来到了我们熟悉的函数位置(单步法具体为什么也不是很懂)
这里写图片描述

那么答案就是00401150喽。

但是我觉得了解一下其他的脱壳方法还是非常非常有必要的。我这里就直接收藏啦,原文地址在这里
https://www.52pojie.cn/thread-259984-1-1.html
内容如下

===============================================================    

     一、单步跟踪法
  脱壳的方法有很多,先来讲脱壳方法中最基础的单步跟踪法。单步跟踪法就是利用OD的单条指令执行功能,从壳的入口一直执行到OEP,最终通过这个OEP将原程序dump出来。然当,在单步跟踪的时候需要跳过一些不能执行到的指令。
  使用单步跟踪法追踪OEP的常见步骤:
  1、用OD载入待脱壳文件,如果出现压缩提示,选择“不分析代码”;
  2、向下单步跟踪,实现向下的跳转;
  3、遇到程序往上跳转的时候(包括循环),在回跳的下一句代码上单击并按键盘上的“F4”键跳过回跳指令;
  4、OD中的绿色线条表示跳转没有实理,不必理会,红色线条表示跳转已经实现;
  5、如果刚载入程序的时候,在附近有一个CALL指令,那么就要按键盘上的“F7”键跟进这个CALL内,不然程序很容易运行起来;
  6、在跟踪的时候,如果执行某个CALL指令后就运行,一定要按键盘上的“F7”键进入这个CALL之内再单步跟踪;
  7、遇到在popad指令下的远转移指令时,要格处注意,因为这个远转移指令的目的地很可能就是OEP。
=============================================================== 
  二、ESP定律法
  ESP定律法是脱壳的利器,是国外友人发现的。有了ESP定律,可以方便我们脱掉大多数的压缩壳。可谓是本世纪破解界中最伟大的发现之一。这里只简单的看一下狭义ESP定律的原理。
  使用ESP定律追踪OEP的常见步骤:
  1、将待脱壳程序载入到OD中,开始就按键盘上的“F8”键单步跟踪一步,这时如果看到OD右边的寄存器窗口中的ESP寄存器的值有没有变为红色,如果发现ESP寄存器的值变为红色,执行第2步;
  2、在OD的命令行窗口中执行命令hrXXXXXXXX,xxxxxxxx就是变为红色的ESP寄存器的值,在输入命令之后,一定不要忘记按键盘上的回车键;
  3、按键盘上的“F9”键让程序运行起来;
  4、使用单步跟踪的方法跟踪到OEP即可。
=============================================================== 
  三、二次断点法
  二次断点是有技巧的下两个断点,在两个断点之后就可以很轻松的找到OEP。
  使用二次断点法追踪OEP的常见步骤:
  1、将待脱壳程序载入到OD中,单击OD的“选项”菜单下的“调试设置”命令,在弹出的“调试选项”对话框中切换到“异常”选项卡,勾选该选项卡下的所有复选框,也就是忽略所有异常;
  2、按键盘上的“ALT+M”组合键打开OD的内存窗口;
  3、在OD的内存窗口中找到“.rsrc”区段,单击该区段后按键盘上的“F2”键在该区段上下一断点;
  4、按“Shift+F9”让程序运行到断点心处,而后再次打开OD的内存窗口,这次在“.rsrc”区段上面的“.code”区段(有的时候就是“.text”)上下一个断点;
  5、按“shift+F9”让程序运行到第二次下的断点处,然后单步跟踪既可以来到OEP。
=============================================================== 
  四、末次异常法
  在脱壳方法中,末次异常法又被称为最后一次异常法,这是最基础的脱壳技术之一。末次异常法脱壳很是简单,但就是这简单的脱壳方法可以挑掉曾经风靡一时的强壳。
  使用末次异常法追踪OEP的常见步骤:
  1、将待脱壳程序载入到OD中,单击OD的“选项”菜单,在弹出的菜单中单击“调试设置”命令,在随后弹出的“调试选项”对话框中切换到“异常”选项卡,清除该选项卡下所有复选框,也就是不忽略任何异常;
  2、连续按键盘上的“Shift+F9”组合键让程序运行起来,记录按键的次数X;
  3、回到OD中,按键盘上的“Ctrl+F2”组合键重新载入程序,按X-1次“Shift+F9”组合键;
  4、在OD右下角窗口中找到“SE句柄”或是“SE处理程序”,记录此处的内存地址;
  5、在OD的反汇编窗口中跟随到上一步记录下的内存地址,并在此内存地址处下一个断点;
  6、按键盘上的“Shift+F9”组合键让程序运行到上一步下的断点处,按键盘上的“F2”键取消此处的断点;
  7、使用单步跟踪法追踪到OEP。
=============================================================== 
  五、模拟跟踪法
  在这章中讲到的众多脱壳方法中,我们首先讲了单步跟踪法脱壳,因为单步跟踪脱壳法是脱壳技术中最基础的方法,在后面其它的一些脱壳方法中总会或多或少的配合单步跟踪法才能顺利完成脱壳工作。便是始终是一次次的按“F8”键来单步跟踪程序,偶尔遇到回跳就跳过执行,这样机械性的操作很是烦人,那么能不能让机器来代替人力,让工具帮我们单步跟踪呢?答案是肯定的,这也就是这节讲的内容——模拟跟踪法。模拟脱壳法就是模拟单步跟踪来进行查找OEP。
  模拟跟踪法的常见步骤:
  1、将待脱壳程序载入OD中,先简单的跟踪一下程序,看看有没有SEH暗桩;
  2、按键盘上的“ALT+F9”打开OD的内存窗口,找到“SFX,输入表,资源”的行,并记录此行的内存地址;
  3、在OD的命令行窗口执行命令“tc   eip<上一步中记录下的地址”,命令执行后就会跟踪到OEP。
=============================================================== 
  六、SFX自动脱壳法
  在上一节,我们使用模拟跟踪法代替手动单步跟踪法进行脱壳。在OD中,不但可以利用模拟跟踪来代替单步跟踪进行脱壳,从而节省劳动力,还有一种SFX自动脱壳的方法也可以节省劳动力,并能快速有效的将程序的壳脱掉。
  使用SFX自动脱壳法脱壳的常见步骤:
  1、将OD设置为忽略所有异常;
  2、在OD的“调试选项”对话框的“SFX”选项卡中选择“字节模式跟踪实际入口”选项并确定;
  3、将待脱壳程序载入OD,待程序载入完成后,会直接停在OEP处。
=============================================================== 
  七、出口标志法
  前面几个脱壳方法中有一个共同点,就是在单步跟踪到popad指令后面不远处的jmp指令的时候,就可以大胆的判断这个jmp指令的目的地址就是OEP。原因很简单,popad指令用于将壳运行之前保存的环境恢复,使原程序能正常运行。有些壳的popad指令很少,我们就可以查看被这种壳加壳的程序的所有popad指令,找到后面存在jmp指令的popad指令,然后来到其后的jmp指令的目的地址,这很可能就是OEP,然后就可以进行dump脱壳了。
  使用出口标志法脱壳的常见步骤:
  1、将待脱壳程序载入OD中,在OD的反汇编客人口中单击鼠标右键,在弹出的右键菜单中单击“查找”→“所有命令”,在弹出的输入框中输入“popad”并按“查找”按钮;
  2、逐一尝试跟踪查找到的所有“popad”指令,最终达到程序的OEP。
=============================================================== 
  八、使用脱壳脚本辅助脱壳
  在脱壳的时候,使用模拟跟踪法可以让OD代替我们单步跟踪程序直到OEP,这样大大提高了脱壳的效率。但是模拟跟踪法并不能跟踪到一些较强的壳的OEP,这时我们可以使用高手们写的脱壳脚本来帮助我们完成脱壳工作,使用脱壳脚本来脱壳要比手动跟踪方便得多。脱壳脚本就是高手们为了方便自己或他人脱壳,把自己手动脱壳的步骤记录下来,保存的一个文本文档。虽然脱壳脚本是一个文本文档,可以使用记事本将其打开,但是轻易不要用这种方式修改脱壳脚本,因为直接修改脱壳脚本,很可能造成脱壳脚本不能正确完成对应的脱壳工作。
=============================================================== 
  九、使用脱壳工具脱壳
  脱壳工具很多,这里只介绍最为实用的全自动脱壳机——超级巡警脱壳工具。
  超级巡警脱壳工具的工作方法:
  超级巡警脱壳工具会自动侦测待脱壳程序所加的壳头,从而判断出带脱壳程序是用哪种壳程序加壳的。如果超级巡警脱壳工具支持对该壳的脱壳,就可以很方便的将程序的壳脱掉;如果不支持对该壳的脱壳,则会给我们一个简单明了的提示。
如恒大所说新手尽量使用脱壳机脱壳。
===============================================================

这个题目尝试了一下别的方法,但是貌似没成功啊.可能不切合实际情况吧,其他方法其实就是在单步调试法的基础上的改进吧。

Music Player

首先用IDA打开发现不知道是啥,明显是加壳过的东西,然后扫描一下发现是这个

这里写图片描述

一开始不知道是什么东西,从网上查找一下资料发现是一个VB程序吧,之前确实没怎么接触过这个,然后就下载了一个VB.Decompiler.Pro.v9.2虽然版本老了一点但是够用了.打开之后发现是VB脚本,还是比较清楚的函数,但是由于不是很懂VB的语法,分析没什么思路,就去学习了一下大佬的思路了。
首先看到,当音乐盒到了一分钟的时候可以看到会有一个弹窗
这里写图片描述

然后大牛们的思路是找到VB函数中的弹窗函数,本来应该是MsgBox,但是貌似全称是rtcMsgBox
这里还是列举一下VB程序一般情况下反汇编一般用什么函数,看这里
http://blog.csdn.net/programmingring/article/details/38374715
那么怎么下断点呢?一开始头疼了半天,这么多程序怎么找…结果人家在LCG版本都写好了…
这里写图片描述

然后我们就来到了弹窗的位置,这个一定是经过判断,不符合要求的一分钟之后弹出的窗口,那么比较的位置应该在之前的位置,而且不会太远,一直在这个函数结束之前总共出现了几次比较,一类基本上是函数调用之后,不像是时间比较,然而这个就很像是匹配1分钟了
这里写图片描述

0xea60==60000,这也太巧了,而且我们看到是jl指令,如果出现小于情况才跳转,在断点这里箭头是灰的,跳转的位置在弹窗函数之后,很像是如果没到时间跳过去继续,如果到点了在这里继续执行弹窗。我们只要将jl改为jmp
然后保存运行,发现过了一分钟之后音乐还可以继续播放,但是莫名报错了!
这里写图片描述

然后就需要找到弹窗的位置了嗯!虽然不知道改怎么办,但是我们隐约可以猜到,之前随着时间移动的时间戳,超过了1分钟是不是没法往后移动了???估计就是一个调用时间戳的位置不对了吧(完全是猜测的…后面验证并不是…)
然后学习一波大佬的思路,既然程序崩溃了,那么在kernel32.RaiseException位置下断点,之后再调用堆栈中可以看到出问题的函数(快捷键Alt+K)
这里写图片描述

我这里kernel32.RaiseException位置是72a10dc9
然后我们看一下问题函数吧
这里写图片描述

就是问题函数是这个,那么我们每次都跳过就好了。
这里写图片描述

呼,太艰难了,自己真菜,题目还是很不错的~(而且最后也没有弄明白,为啥标签就变了…懒得看了…)

Replace

发现真是一道题都没法自己独立完成了…
首先显示看看有壳没,索性没有

这里写图片描述

IDA打开看一下关键点,发现可以找到什么Correct,过去一看再是这个东西….
这里写图片描述

DialogFunc就是一个主函数的功能嘛,但是下面那一坨是啥玩意…没头绪看一下OD,发现Correct,然后根据Correct的位置和跳转的流程可以断点到输入数字Check之后,起始在这里
这里写图片描述

不说别的一直单步下去,发现在一个地方崩溃了???WTF
这里写图片描述

但是为什么崩溃呢?我们不开别的什么流程,我们看一下这句是要用ds段eax值最为地址,但是这个时候eax值是啥…
这里写图片描述

虽然不知道这个是怎么生成的,但是这个也太大了!(事实上这么大的值不就是来自于上面的额…见下图吧)
这里写图片描述

然后我们只要改一下一个合适的位置先跳过去再说,然后走到后面就牛逼了,修改了源程序了..最后程序变成了这样,总觉的很像是防静态的一种手段,看看后面具体想要干什么吧
这里写图片描述

然后我们千辛万苦跳回去了…发现在修改Correct之前还有一个jmp…正好把我们想要的函数跳过。
这里写图片描述

那么,这个题目到底要干嘛!!!现在突然灵光一现!我们输入的是一个10进制数字把!然后我们看本题的第二张图里,明显这里就是输入的位置
这里写图片描述

我们记住这个位置是4084D0,然后我们再回到崩溃的位置之前看一下,eax的来源就是来自输入数字加上一个数字(这个程序之前我们改变过了记得不,我们已经变成了上上上张图那样)
我们输入的数字首先经历了+1,然后跳出函数之后再+1
这里写图片描述

之后我们跳转到了这里!
这里写图片描述

明显这个是那个db 81扰乱了程序的翻译,那么我们看一下从404674一直到40467中间是什么指令!翻译一下
这里写图片描述

这就精彩了,就是再我们储存输入的位置又加上了0x601605C7
还没完,后面还在+1+1
这里写图片描述

然后回到了40106啊,至此这个40466f函数才完成,总结一下,计算方法是
输入值+2+0x601605C7+2

之后程序恢复了40466f打那个90 nop的功能,然后还是到了打两个nop的程序,再说我们到了Correct之前有一个jmp,好了我们这次的目标就是让这个nop把那个jmp打掉!

这里写图片描述

目标地址是0x401071我们计算出上面的溢出点在哪即可,注意要用到溢出嗯
这里写图片描述

可能比较乱啊,不过确实是一道好题!自己真菜!

ImagePrc

这个题目一看就是很明确了,界面是一个类似画板的东西,可以网上画图案,然后点击check,估计就是文件中存着一个图片,然后和你画的匹配一下这样子。然后反编译一下看代码

这里写图片描述

然后很容易我们就看到前面是处理图片的,然后图片的头大小是40,然后
这里写图片描述

然后上面这个东西包含着图片的长和宽,这玩意很重要哇,在后面比较的时候我们注意到大小是90000,所以长宽很重要,虽然我们现在看不到,但是这个实可以在调试过程中看的到的。然后通过调试我们知道高是150,那么对应的宽就是600了,然后我们简单判断一下,匹配的内容一定实在文件的数据段中,所有我们dump这个东西,找到了位置应该是0x47e060,而且计算一下90000大小就是到了0x493ff0,恰巧到这里也就结束了。然后我不太会dump,然后用OLLYDB的复制到文件弄得…形式如下

这里写图片描述

当然了,这个是非常笨的方法…然后写了个脚本跑一个图片出来

#_*_coding:utf-8_*_
import hashlib
from PIL import Image  
file_path = r'dump.txt'
content = open(file_path,'r').readlines()
a = []
for ooo in content:
    sss = ooo.replace('\n','')
    sss = sss.split(' ')
    for i in sss:
        if i =='FF' or i == '00':
            a.append(i)
print len(a)
img=Image.new('RGB',(150,600),(255,255,255))
loding = img.load()
sum=0
for x in range(0,150):
    for y in range(0,600):
        if a[sum]=='FF':
            loding[x,y]=(0,0,0)
        else:
            loding[x,y]=(255,255,255)
        sum+=1
        if sum>90000:
            break
img.show()

然后得到图片,旋转一下

这里写图片描述

最终得到答案…但是反映了我不会dump数据…我的天..补课补课…

当然这个资源可以用其他的工具提取,比如eXeScope啊,然后还有一种写法(这个的输入dump是bin文件啊)

#_*_coding:utf-8_*_
import hashlib
from PIL import Image  
file_path = r'dump'

width=200  
height=150  

f=open(file_path,'rb')  
data=f.read()  
p=Image.frombytes('RGB',(width,height),data)  
p=p.transpose(Image.FLIP_TOP_BOTTOM)  
p.show()  

事实上之前的长度600实我自己推得,题目中其实利用的150*200的图像,只不过再验证的时候用到了每一个像素点的三元组,所以验证的长度是150*200*3==90000.我们最开始的写法就是相当于把长拉长了,因为是00或者ff所以结果没有影响。

Position

这个题目,咋说呢,乍一看真的很吓人,其实很简单,只要看懂了就行,首先我们看一下很明显得地方

这里写图片描述

就是我们界面得地方,然后这个是MFC程序,代码中动态检查两个文本框是否有输入。通过文档我们知道了一部分信息

1.serial的内容是76876-77776
2.密码的最后一位是p

然后进入关键函数查看。这个长的令人发指…但是我们只要仔细看结构和逻辑基本上都是很简单的。就算静态看不懂,我们只需要动态调试一下也就知道这是什么情况了(这个处理确实比较简单,中间很多就是简单的加和,然后将int型转换字符型,然后匹配),然后简单总结一下就是

程序得流程
1.首先读入两个字符串 Name和Serial
2.验证Name得长度是不是4
3.验证Name组成得字符是不是都是a-z
4.验证Name中是否存在相同得字符
5.验证Serial得长度是不是11,且第6位是不是'-'
6.一大长串得验证,具体看代码吧

然后关于那一坨东西,我们只需要看代码就一下子明白了

#_*_coding:utf-8_*_
import hashlib
serial = '76876-77776'
s = 'abcdefghijklmnopqrstuvwxyz'
first = []
second = []
for s1 in s:
    for s2 in s:
        value1_1 =  (ord(s1)&1)+5
        value1_2 =  ((ord(s1)>>4)&1)+5
        value1_3 =  ((ord(s1)>>1)&1)+5
        value1_4 =  ((ord(s1)>>2)&1)+5
        value1_5 =  ((ord(s1)>>3)&1)+5
        value2_1 =  (ord(s2)&1)+1
        value2_2 =  ((ord(s2)>>4)&1)+1
        value2_3 =  ((ord(s2)>>1)&1)+1
        value2_4 =  ((ord(s2)>>2)&1)+1
        value2_5 =  ((ord(s2)>>3)&1)+1  
        check1 = value1_1+value2_4
        if check1 != int(serial[0]):
            continue
        check2 = value1_5+value2_5
        if check2 != int(serial[1]):
            continue
        check3 = value1_3+value2_2
        if check3 != int(serial[2]):
            continue        
        check4 = value1_4+value2_1
        if check4 != int(serial[3]):
            continue        
        check5 = value1_2+value2_3
        if check5 != int(serial[4]):
            continue
        first.append(s1+s2)
        #print s1,s2
for s3 in s:
    for s4 in s:
        value1_1 =  (ord(s3)&1)+5
        value1_2 =  ((ord(s3)>>4)&1)+5
        value1_3 =  ((ord(s3)>>1)&1)+5
        value1_4 =  ((ord(s3)>>2)&1)+5
        value1_5 =  ((ord(s3)>>3)&1)+5
        value2_1 =  (ord(s4)&1)+1
        value2_2 =  ((ord(s4)>>4)&1)+1
        value2_3 =  ((ord(s4)>>1)&1)+1
        value2_4 =  ((ord(s4)>>2)&1)+1
        value2_5 =  ((ord(s4)>>3)&1)+1  
        check1 = value1_1+value2_4
        if check1 != int(serial[6]):
            continue
        check2 = value1_5+value2_5
        if check2 != int(serial[7]):
            continue
        check3 = value1_3+value2_2
        if check3 != int(serial[8]):
            continue        
        check4 = value1_4+value2_1
        if check4 != int(serial[9]):
            continue        
        check5 = value1_2+value2_3
        if check5 != int(serial[10]):
            continue
        second.append(s3+s4)
        #print s3,s4
print first
print second
for p1 in first:
    for p2 in second:
        value = p1+p2
        bit = []
        flag = 1 
        for check in value:         #一定要注意需要验证4位数之间不能出现重复得字母
            if check in bit:
                flag = 0
                break
            else:
                bit.append(check)
        if flag ==1:
            if value[3]=='p':       #题目给的限定条件,最后一位是p
                print value

然后得到了3歌结果,看到了有意义的一个bump

Direct3D FPS

这个题目一开始就吓我一跳,这是CS?然后解压可以看到一个data文件夹,一个可执行文件,一个dll(警觉),然后发现卡的不行,看到FPS貌似是帧数,但是也不知道要干啥,所以就打开IDA随便看一下,看一下字符串

这里写图片描述

感觉可能题目的意思就是想办法让我们结束战斗吧,但是…这真的是简单题目???!!!
这里写图片描述

然后后面有一个弹窗,感觉应该没什么问题…所以我们进行一下尝试把(最后证明以后碰到这种东西不要虚,直接上去试试…)首先我们需要解决一个问题,就是我们不可能真的做到game over的条件了(没分析也不知他是什么条件要求,但是我们可以),所以就胡乱改一下把…修改跳转指令
这里写图片描述

然后就过去了,但是我们看到这里是乱码,这就确信了这个就是答案,你不可能通关了给你个乱码把!
这里写图片描述

所以需要知道有没有别的地方调用修改了这个地方,要不说IDA是个好东西…可以直接看到啊(所以前面不是很有必要了…因为静态居然可以看到…)然后我们看一下静态的内容长度应该在56之内把
这里写图片描述

然后看到另一个关键的函数段
这里写图片描述

看到这个关键的内容,这个result如何要处理的话应该时从0遍历的。而且这个抑或的byte_409184是动态获取的,而且感觉这个所谓的*4什么的只是一个索引的作用。我们姑且就让他从0-52跑一遍,这个函数触发的时候时射击的时候,但是不知道它到底是做什么的…
而且貌似result也不是从0-52,一直是-1啊…然后干脆走一走地图…发现了这个小东西
这里写图片描述

干他一枪,发现返回的result变了额!
这里写图片描述

然后经过测试发现,每一个小人应该是有一个不同的ID一样的东西,result返回的就是这个东西!这下子明白了,也就是说胜利的条件是打过所有的小人呗!然后每个小人会处理一位…好吧,明白了
不过我们不能一个个都打把!而且这个每次修改result的值?这太麻烦了…然后忍不住查了一下别人怎么做的…IDApython!!!

print bytearray( [(Byte( 0x1b7028+i ) ^ Byte(0x1b9184+(i*0x210))) for i in range(56)] )

真是学习了一波老哥^_^(记得运行的时候再执行脚本)

这里写图片描述

其实我们如果可以找到byte_409184索引的位置也是没问题的…,每一个对应的位置是byte_409184+0x210*n,最后观察发现是有规律的,就是byte_409184+0x210*n==4*n
然后也可以直接写解密脚本

import hashlib
flag = ''
cipher = [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(len(cipher)):
    flag += chr(cipher[i]^(i*4))
print flag

回头想想还是挺简单的,但是千万别被题目吓住额…

Ransomware

首先拿到了程序用 IDA反编译一下发现貌似呗加壳了,然后查一下壳吧,发现匹配不出来,但是貌似有什么UPX这个字段,很敏感

这里写图片描述

然后我们利用ESP定律进行脱壳吧,找到了程序得真正入口点是
这里写图片描述

然后利用OLLYDB得dump工具进行脱壳,然后进一步看一看程序到底是啥!结果解压出来了一个10M多得东西???!!!woc,不会吧…而且我们继续观察一下貌似关键得代码部分会有很多很多得混淆…这就尴尬了…从0044A775往上有很多废物代码
这里写图片描述

真实垃圾限制了我的想象力,然后需要尝试IDApython解决这个事情!然后我明明写的代码没什么问题,但是死活就是得不到结果…

start = 0x401006
end = 0x4135CE
for i in xrange(start,end):
    PatchByte(i,0x90)

start = 0x4135E9
end = 0x44A775
for i in xrange(start,end):
    PatchByte(i,0x90)

结果调出来Graph view然后按下F5就行了,不明白为什么…

从从网上还看到有人直接匹配文件中得特殊字符

这里写图片描述

data = open('111.exe','rb').read()
data = data.replace('\x60\x61\x90\x50\x58\x53\x5b','\x90\x90\x90\x90\x90\x90\x90')
open('777.exe','wb').write(data)

比较取巧但是也是解决得方法!然后我们就可以问题具体得加密流程了

这里写图片描述

真正得算法非常简单,但是我们需要注意得是没有办法根据反编译找出密钥,我胡乱输入一个数字后,这时候我们看一下file得规律
这里写图片描述

这个明显是有规律得,但是我们也不是很确定,之后尝试果真有不小问题…然后我们注意到TXT中得
这里写图片描述

exe是用一些固定得明文串的,这算是小技巧吧,利用一下
这里写图片描述

key1 = [0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,0x6d,0x6f,0x64,0x65]
key2 = [0xc7,0xf2,0xe2,0xff,0xaf,0xe3,0xec,0xe9,0xfb,0xe5,0xfb,0xe1,0xac,0xf0,0xfb,0xe5,0xe2,0xe0,0xe7,0xbe,0xe4,0xf9,0xb7,0xe8,0xf9,0xe2,0xb3,0xf3,0xe5,0xac,0xcb,0xdc,0xcd,0xa6,0xf1,0xf8,0xfe,0xe9]
flag = ''
for i in range(len(key2)):
    flag += chr(((~key2[i])%256)^key1[i])
print flag

得到密钥letsplaychess,然后去解密程序即可,得到了程序运行不起来,发现还是UPX加壳,脱壳之后继续看看源码算了…找到了结果

这里写图片描述

然后看到了人家得wp发现一个用IDApython处理将冗余得sub401000函数去掉的方法!Σ(っ °Д °;)っ,学习一波得…

#_*_ coding:utf-8 _*_
import idaapi
ea = 0x0044A775     #_main函数实际作用的位置
StartAddress = LocByName('_main')  #获得_main函数的起始地址
func = idaapi.get_func(StartAddress)    #获得目标函数,输入地址是函数的起始地址
EndAddress = func.endEA     #获得函数的结束地址
while ea <= EndAddress:     #遍历函数
    ea = FindCode(ea,SEARCH_DOWN | SEARCH_NEXT) #找到代码位置
    if GetMnem(ea) == 'call' and GetOpnd(ea,0) == 'sub_401000': #匹配字符串,前面是助记符,后面是操作数
        for i in range(5):      #长度是5是观察出来的call sub_401000
            PatchByte(ea+i,0x90)    #打patch喽

果真IDApython还是很厉害的!效果如下

这里写图片描述

学习到了,膜

Easy_ELF

做个简单的先换换脑子

这里写图片描述

简单明了直接了当…来到关键函数简单一分析就得出结论了…

L1NUX

Twist1

好好做提了…这个题目首先运行没什么问题,然后IDA看也没什么,不看具体内容先,然后OLLYGDB跑的时候会崩溃?瞬间警觉,然后返回IDA看一下代码发现其实代码不全,估计是一个花指令的东西。我们一步一步来(我没分析过,就是自己试试好了)首先是

这里写图片描述

在这个地方修改了原来的代码,之后变成了这个
这里写图片描述

可以看一下这个是啥东西啊,是防止静态的一种简单的花指令
这里写图片描述

可以看到,这个时候al=0x9d
这里写图片描述

看看变成了什么
这里写图片描述

然后和前面有一个pushf,而且这里我们还要动态修改一个地方,最后成了
这里写图片描述

可以看到最后跳回了0x40700D,上面的0x407030函数完全就是一个可执行花指令函数。
这里写图片描述

再之后其实没什么,就是将0x40702F改成了0x407008,然后又去call了一下0x407030,就是又是一个花指令函数的过程,之后会跳到
这里写图片描述

后面没法继续完全分析了,发现越来越多…我觉得应该是某些壳…要不然也太多了…不管怎样还是继续调试,这个花指令就是防止静态的调试,再动态过程中不断修改代码达到跳转到主函数的目的,最后找到一个长跳转很像OEP

这里写图片描述

这里写图片描述

可以看到了push什么什么,很像主函数的东西喽,然后实验成功脱壳.然后看了一下代码就很简单了,貌似就一个判断函数而已,前面都是字符串的输入输出
这里写图片描述

然后继续想动态调试调试出最关键的地方,但是还是没有解决一Ollygdb调试就崩溃…what?但是这里崩溃的位置是这个
这里写图片描述

调试的时候发现除以0了,所以先nop掉再说,后面所谓的比较函数sub_401240只是一个假象,首先是将输入字符串的数值放到了byte_40B970之中,然后来了个大跳转???
这里写图片描述

但是那个地方什么都没额…我觉得这个操作应该是故意改错的吧?也不对啊…那源程序怎么就跑的起来…百思不得其解…参考一下大牛说那里有东西???!!!what???不知道说什么好了…不知道什么原因dump下来就没东西…只能每次都脱壳?结果看一下还真有东西…(为啥啊!)
这里写图片描述

调用了什么ZwQueryInformationProcess
调试的过程中发现,如果这个位置不匹配就会陷入死循环
这里写图片描述

总共拷贝了16个字节到这个地方…但是我发现还是死循环…在验证00407275时候死活过不去???这又是啥…复制的地址是7757E990,应该是系统函数,后面找到了是ntdll.dll,系统函数?这个还能错得话就是…系统不对???想到了Readme…
这里写图片描述

老老实实放回32位XP下跑吧…
这里写图片描述

造孽啊…果然放到了XP下就没任何问题了…而且能够验证之前dump下来得脱壳文件确实不行…会运行崩溃…
然后我们继续分析把,刚刚拷贝得16个字节得内容就是我们后面要调用得函数,再往后调用得过程中OLLydbg停止了,是反调试技术了。查找了资料是queryInformationProcess()函数相关得反调试函数
这里写图片描述

然后通过查找资料调用得函数应该具体是ProcessDebugPort(0x7)和ProcessDebugObject-Handle(0x1E)还有ProcessDebugFlags(0x1F),具体是什么简单介绍一下

ProcessDebugPort(0x7)
进程处于调试状态,系统会为它分配一个调试端口,ProcessInformationClass参数的值为ProcessDebugPort(0x7).若程序处于非调试状态,则变量dwDebugPort的值设置为0,若进程处于调试状态,则值设置为0xFFFFFFF.

ProcessDebugObjectHandle(0x1E)
调试进程时会生成调试对象,函数的第二个参数值为ProcessDebugObjectHandle,调用参数后就能获取调试对象句柄,进程处于调试状态时,调试对象句柄的值就存在,若进程处于非调试状态,则调试对象句柄值为NULL.
ProcessDebugFlags(0x1F)
检测debug flag调试标志的值也可以判断是否处于被调试状态,函数 的第二个参数设置为processdebugflag(0x1)时,调用函数后通过第三个参数即可获的调试标志的值,若为0,则进程处于被调试状态,若为1,则进程处于非调试状态。

然后直接全部nop掉好了
然后继续,取出了第一位和第七位放到了新的内存中(再次提醒一下输入的地址事0x40b970)

这里写图片描述

后面调着调着又又又结束进程了!!!!这回又是啥…然后找到出问题的地方,发现使用了GetThreadContext函数,作用是获取硬断点的内容…之前我下了硬断点,所以这里就gg了…然后解决的方法是再每次jnz跳转的时候修改掉寄存器的值或者test eax之前将eax置零。
然后我们可以看到一个东西!
这里写图片描述

这个就是我们之前输入字符串第七位与0x36抑或的值,比较是不是0x36,那么就是说第七位已经是末尾之后了,字符串很可能是6位(7位以下嘛)

然后第一位的匹配,我实在懒得再去截图了,是这样的

1.将第一位ror al 6
2.将移位后的值和0x49比较

得知第一位是R
然后继续观察可以得到

第二位 ^0x20==0x69  I

第三位 ^0x77==0x35  B

第四位 ^0x21==0x64  E

第五位 ^0x46==0x8   N

第六位 rol dl 4 之后与0x14比较

最后得到了整个解题的答案…

RIBENA

这里写图片描述

woc…这题实在是挺难的…搞了两三天才弄完…真是…总结一下这个题目的考点…

1.首先本来是脱壳,但是不知道为什么脱壳后dump下来的数据是残缺的,现在怀疑是程序本身的东西,可能加了个线程什么的实现的,实际上我们知道OEP就行了
2.反调试技术,里面有一些坑点,比如调用的queryInformationProcess()检测进程是否为调试状态,再比如GetThreadContext检测程序是否有硬断点...
3.然后中间有内存的来回切换,需要十足的细心
4.考验用ollygdb的运用能力

总之对我来说确实很难了,太菜了…/(ㄒoㄒ)/~~

AutoHotkey1

查壳看不出来,但是还是需要手动脱壳把应该(至少需要知道OEP在哪里)
然后我们找到OEP应该是

这里写图片描述

然后我找到了输入的地方,并在后面下了断点,然后再输入之后歪打正着找到一个….
这里写图片描述

然后输入54593f6b9413fc4ff2b4dec2da337806就会显示
这里写图片描述

什么鬼,但是题目肯定不是这么做的,提交结果也不对,我认为只是误打误撞找到了部分答案。其实我一开始一直没弄懂Readme几个意思,后来明白其实需要提交AuthKey吧,然后我们需要找到DecryptKey和EXE’s Key了。

使用upx -d解密文件,发现是这样的

这里写图片描述

然后再GDB里面找到字符串,然后跟到了这里
这里写图片描述

然后就看到eax被赋值时3了,然后用IDA大概看一下发现这个应该时判定文件是否被修改过而已。然后这里我们将je条件改变使之能够跳过这一步。这附近的逻辑大概是这样的
这里写图片描述

所以这个地方的函数判断也非常重要,必须通过,否则程序也无法运行
这里写图片描述

然后点进去看,发现时这样的
这里写图片描述

然后观察得到 sub_450DCA之中用到了多次 sub_450ABA,而且另一个分支之中 sub_450ABA也用到了很多次,于是这应该是一个类似验证的函数,而且我们观察到我们upx -d之后函数会在这里附近结束,估计这个时验证文件是否被修改的函数。那么如何验证,估计就有一个MD5比较吧!试试就知道了。
使用源文件(没有改过的),然后在 sub_450DCA下断点,然后一步步看。
这里写图片描述

在这一步得到了寄存器的值220226394582d7117410e3c021748c2a

再结合前面的…MD5解密得到

isolated pawn

woc。。。这还是投机取巧了,没让你分析具体的算法什么的,这个题目就是看你逆向的一些套路了,能不能大概猜到他的作用,需要多尝试,多猜想验证…(本题后面都是参考大佬了,太菜了…套路不够深…)





















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值