BUUCTF-[2019红帽杯]Snake&&Dig the way

[2019红帽杯]Snake

题目下载:下载

下载完文件是一个用C#编写的untiy程序,对于这种程序果断用dnSpy查看Assembly-CSharp.dll

找到如下位置BUUCTF-[2019红帽杯]Snake&&Dig the way_第1张图片

发现这些函数都导入了Interface函数,那找到这个动态链接库的位置,用ida打开,f12搜索关键字BUUCTF-[2019红帽杯]Snake&&Dig the way_第2张图片

发现了You win!,跟进BUUCTF-[2019红帽杯]Snake&&Dig the way_第3张图片

发现这个代码很长,但是这个GameObject()函数只有一个a1参数,并且他也参与了运算BUUCTF-[2019红帽杯]Snake&&Dig the way_第4张图片

那他是不是关键点呢,由上图可以知道a1的范围[0,99],所以让a1值从0-99爆破,这里用到了ctypes库,即加载一个dll,值得学习,参考别人的wp,代码如下BUUCTF-[2019红帽杯]Snake&&Dig the way_第5张图片

最后flag为flag{Ch4rp_W1th_R$@}。

知识点补充:

ctypes 是Python的外部函数库。它提供了与 C语言兼容的数据类型,并允许调用 DLL 或共享库中的函数。可使用该模块以纯 Python 形式对这些库进行封装。


载入动态链接库:
       通过操作这些对象的属性,你可以载入外部的动态链接库。cdll载入按标准的cdecl调用协议导出的函数,而windll导入的库按stdcall调用协议调用其中的函数。oledll也按stdcall调用协议调用其中的函数,并假定该函数返回的是 WindowsHRESULT错误代码,并当函数调用失败时,自动根据该代码甩出一个OSError异常。

       在 Linux 下,必须使用包含文件扩展名的文件名来导入共享库。因此不能简单使用对象属性的方式来导入库。因此,你可以使用方法LoadLibrary(),或构造 CDLL 对象来导入库。

Dig the way 

题目下载:下载

查壳:BUUCTF-[2019红帽杯]Snake&&Dig the way_第6张图片

无壳,载入IDA

先看第一部分:BUUCTF-[2019红帽杯]Snake&&Dig the way_第7张图片 发现有三个函数,看func0BUUCTF-[2019红帽杯]Snake&&Dig the way_第8张图片

很明显这是交换两个元素的位置。

看第二个函数:func1BUUCTF-[2019红帽杯]Snake&&Dig the way_第9张图片

 返回值是一个可能大于0,小于0或者等于0的数

看第三个函数func2:BUUCTF-[2019红帽杯]Snake&&Dig the way_第10张图片

 发现这个函数的返回值是一个恒大于2的数

继续往下看main函数的其他部分BUUCTF-[2019红帽杯]Snake&&Dig the way_第11张图片

打开“data”文件进行读操作,文件指针为file_ptr,然后使用feek函数,首先让文件指针指向文件的末尾,用ftell函数来求文件指针(在末尾)对于文件首的偏移字节数,所以v14就是读取的文件中的字符长度,然后在用feek函数指向文件头,用ftell求文件指针(在文件头)相对于文件头的偏移,所以v13为0,然后用for循环读取data文件中字符到v7_20中。

看main函数第三部分:BUUCTF-[2019红帽杯]Snake&&Dig the way_第12张图片

v5是读取字符串的长度,与v14长度相同。然后主要看这个while循环和get_key。先进入get_keyBUUCTF-[2019红帽杯]Snake&&Dig the way_第13张图片

发现只要进入get_keu函数就可以输出flag了,执行get_key前提是if条件的v9==0,但是按照前面的程序执行的话,v9不可能为0呀!!!

看一下while循环:

执行第一次while循环时,参数为(v8,3,4),执行func0函数,即v8[3]和v8[4]交换位置,而v8[3]是v9值为3,v8[4]是v10值也是3,所以相当没啥变化,返回1给v8[1]。

执行第二次while循环时,参数为(v8,1,2),执行func1函数,经过计算知v8[2]=2。

执行第三次while循环时,参数为(v8,2,3),执行func2函数,经过计算v8[3]=6,即v9=6

通过上面知道只有第三次while会影响v9的值,所以只用想办法让第三次while循环使得v9==0即可,v9的值是通过函数返回求得的,但是func2的值恒大于0,func0只是交换位置没有赋值,只有func1的返回值可能是0,所以让第三次while循环执行func1就行

看一看这些变量在栈中状态BUUCTF-[2019红帽杯]Snake&&Dig the way_第14张图片

 

 发现str函数应该有20个才对,但是读取数据的时候并没有严格限制是20个,所以有可能在data文件中读取的数据多余20个就会把栈中其他的数据覆盖掉,所以我们可以覆盖掉v9的值,让其为0。

首先通过func0函数交换func1与func2函数执行顺序,然后让第三次while循环执行func1时,让func1函数返回值为0就行,所以执行第一次while时,让参数为(v8,7,8),这样交换func1,func2执行顺序,然后执行第三个while循环时,参数为(v8,2,3),v8[2]=2,让v8[3]==-1,这样返回值就为0,v9就会变为0,所以创建一个data文件,如下(32位时-1在内存中为FF FF FF FF )这样,在执行一下,就会自动跳出flag

函数补充:

feek()BUUCTF-[2019红帽杯]Snake&&Dig the way_第15张图片BUUCTF-[2019红帽杯]Snake&&Dig the way_第16张图片

ftell()

long ftell(FILE *stream):函数 ftell 用于得到文件位置指针当前位置相对于文件首的偏移字节数。在随机方式存取文件时,由于文件位置频繁的前后移动,程序不容易确定文件的当前位置。

 

 

 

 

你可能感兴趣的:(re简单题,ctf,re)