Pwn01

SCUctf2018 Pwn00

师傅选择了这道入门栈溢出来作为我玩pwn的第一道题。
先是查一下文件
image1

首先是题目 丢进IDA看了发现有个magic函数调用了system帮我们解决了问题(爽到)
然后就是调调调
image1

从IDA的结果中我们容易看到buf这个局部变量距离ebp的距离是0x20h.我们只需要传一个0x20h的数据把局部变量预留区域塞满,再填掉前一栈帧的ebp,就可以用我们写的返回地址覆盖原函数的返回地址,进而调用程序预留的后门(magic)

之后就快乐写jo本

image1

写完能跑

成了。

Pwn00(菜鸡的Pwn入门)

一、写在最开始

这是一个菜鸡学习pwn的记录。主要作用是帮助自己进行记忆因为我是金鱼精,防止自己忘记必要知识,方便复习。
当然如果这个系列的文章帮到你了,我会很荣幸。

二、入门基础知识

首先,我们需要知道函数调用的相关信息,以及栈溢出的基本知识,(在我入门的这最初一段时间里我几乎可以遇见地会一直和栈溢出死磕到底。)栈溢出的知识又有很多相关的东西。我把这篇文章命名为00是因为我将会随时修改这篇文章里面存在的基础知识。大部分会是增添。

①栈帧

Welcome

我是一个来自中国成都的二进制学习者。目前在学习逆向的过程中。水平有限,欢迎交流。

除了二进制以外的爱好是兵击(hema)和贝斯。

拼尽全力 然后 剩下的事情就是命运说了算了。

181004(隐藏进程)

一、隐藏进程:

隐藏进程:隐藏特定进程的技术(stealth process),专业术语叫Rootkit,指通过修改(Hooking)系统内核来隐藏进程、文件、注册表的一种技术。
IAT钩取通过操作进程的特定IAT值来实现API钩取,而API代码修改技术则将API代码的前五个字节修改为JMP XXXXXXXX来钩取API。
(1)正常调用API时
调用API时,首先使用CALL 指令调用API,在相应API执行完毕后,返回到调用代码的下一条指令的地址处。
(2)钩取之后:

首先把dll注入目标进程,API起始地址5个字节代码被修改为JMP XXXXXXXX(仅修改五个字节),在我们的XXXXXXXX的位置,首先把APi修改回原样然后调用一次,之后钩取。
注:当API的前五个字节是我们修改过后的时,也即API被钩取。
使用API代码修改技术可以钩取进程中使用的任意API。要钩取的API代码长度要大于五个字节但是所有API代码长度都大于5个字节。

进程隐藏,用户模式下最常用的是ntdll.ZwQuery-SystemInformation()API钩取技术。

为了隐藏某个特定进程,要潜入其他所有进程内存,钩取相关API。

用户模式下检测进程的API分为2类
1、 CreateToolhelp32Snapshot()&EnumProcess()

2、 ZwQuerySystemInformation()
该API可以获取运行中的所有进程信息(结构体),形成一个链表。操作该链表即可隐藏相关进程。
因此我们需要“全局”(global)钩取来实现钩取系统中运行的所有进程的ZwQuerySystemInformation()API。

练习实例

1、练习#1
在虚拟机中按照书上的格式使用书中提供的程序。但是注入失败。经检测发现dll注入正常,经过分析可能是虚拟机自带的procexp是魔改版本,可以保护自身不被dll注入。所以“notepad.exe”并未消失.

使用CreateToolhelp32Snapshot()获取系统中运行的所有进程的列表,然后使用Process32First()与Process32Next()将获取的进程信息存放到PROCESSENTRY32结构体变量pe中进而获取进程的PID.

在代码的注入中,分析源代码发现进程PID小于100的程序我们就没有操作。(系统进程)

这段代码中,我们先创建名为”.SHARE”的共享内存节区,然后创建g_szProcName缓冲区,最后再由导出函数SetProcName()将要隐藏的进程名称保存到g_szProcName中。

JMP加地址 E9 XXXXXXXX 其中XXXXXXXX=要跳转的地址-当前指令地址-当前指令长度

###二、全局API钩取
全局API钩取针对的进程为:(1)当前运行的所有进程(2)将来要运行的所有进程
Kernel32.CreateProcess()被用来创建新进程。因此如果钩取了Kernel32.CreateProcess()那么之后父进程使用它创建的所有子进程都会被注入。
但是要注意(1)还要钩取CreateProcessA()、CreateProcessW()2个API(ASCII和Unicode版本) (2)微软部分软件会调用CreateProcessInternalA/W这两个上述API内部的函数。(若可能,尽量钩取低级API) 。
ntdll.ZwResumeThread()API ,比CreateProcess()更低级,钩取效果更好。
ZwResumeThread()函数在进程创建后,主线程运行前被调用执行(在CreateProcess()API内部调用执行)。但该API尚未被公开,可能会被更改,因此可能在未来的时间钩取操作无法运行。

练习实例

按照书中所说我们把”stealth2.dll”导入系统目录的system32文件夹,并运行了程序

这次和书中的预期结果相同,procExp进程和任务管理器中的“notepad.exe”进程隐藏了。
与实验1的不同是在本次的stealth2.dll中,添加了钩取CreateProcessA()和CreateProcessW()API的代码.
值得注意的是钩取尚未公开的API时,一定要检查它在当前的OS版本中能否正常运行。

###三、 利用“热补丁”技术钩取API
API代码修改技术修改过后的API每次被在程序内部调用时,我们的钩取函数就会被调用执行,不断的“脱钩”/挂钩。造成整体性能地下,更严重的是在多线程环境下还会产生运行时错误。当一个线程尝试运行某段代码时,若另一线程正在对该段代码进行“写”操作,这时就会出现冲突,最后引发运行时错误。
因此,我们需要“热补丁”(Hot Patch/Hot Fix)技术比修改5个字节代码的方法更稳定。热补丁将会修改7个字节代码。
常用API的起始代码部分会以”MOV EDI,EDI”开始(IA-32:0x8BFF),API代码上方有5个NOP指令(IA-32:0x90)。
MOV EDI,EDI 2个字节,NOP 1个字节。 这七个字节的指令没有任何意义。
我们将API起始代码之前的5个字节修改为FAR JMP指令,跳转到用户钩取函数处,然后将API其实代码的2个字节修改为SHORT JMP指令。通过这种我们称为“二次跳转”的技术就完成了对指定API的钩取操作。通过热补丁技术钩取的API并未对原API进行修改,可以用”原API地址+2”开始执行原API。

练习实例

按照书中的实验原理很容易理解,我们来看源码。

在这里的pBuf【5】申明为{0xE9,0},之后使用两次memcpy函数先把 “JMP XXXXXXXX”的XXXXXXX写进去,然后把整个“JMP XXXXXXXX”写到API前的那五个字节。然后用memcpy把MOV EDI,EDI替换为JMP YY指令。
值得注意的是热补丁API钩取技术使用时必须满足它的使用条件。如果不满足使用条件那么就只能使用五字节代码修改技术。
Ntdll.dll中提供的API代码都较短,钩取这些API的时候有一种非常好的方法,将原API备份到用户内存区域,然后使用5字节代码修改技术修改原API的起始部分。 由于API代码较短且代码内部地址无依赖性,因此非常适合使用这一技术钩取。但这一技术需要处理重定位的问题。

180921(计算器中显示字)

通过DLL注入实现IAT钩取的技术。较为好实现,但是如果目标API不在目标进程IAT中,就无法使用该技术.(动态加载dll=凉凉)

为了确认需要钩取的API,可以使用PEView查看导入的API,然后对API进行文档查询.

查询发现计算器的SetWIndowTextW()、SetDlgItemTextW()比较引人注目(???),而后者又调用了前者,所以我们假设只要钩取前者就OK.

(API后面跟的是W就是说是宽字符(Wide character)版本.若后面跟的是A则是ASCII码字符版本。宽字符说的是Unicode码。)
XySher
跟着流程查看栈窗口。
XySher
覆写时要逆序进行。每个Unicode中的汉字占2个字节
XySher
程序开始时,PE装载器会将user32.SetWindowTextW()API地址记录到该地址(01001110),该地址是IAT区域。

而我们钩取IAT过后,将IAT保存的API起始地址变为用户函数的起始地址。

像这样,先向目标进程注入用户DLL,然后在进程的IAT区域中更改4个字节大小的地址,就可以轻松钩取指定API。这种技术也称为IAT钩取技术。

练习实例
XySher
诶这次居然成了 舒服
XySher
...下载下来的是原版 难免 难免.

在实际操作中,必须先确定提供API的DLL已经正常加载到相应进程,如果相应API在钩取前尚未被加载,则应该先调用LoadLibrary()API加载它。

把数字和中文进行1:1的对应可以不加任何修改地使用原缓冲区。

在IAT中查找到user23.dll对应的IID后,在IAT中查找SetWindowTextW API的位置,然后修改其中内容,从而实现对API的钩取。
MySetWindowTextW()函数主要有2个功能,它首先将阿拉伯数字转换为中文数字(字符串),然后调用原来的user32.SetWindowTextW()API。

隐藏进程
全局钩取(Global Hooking),能钩取所有进程。
修改API代码(Code Patch)实现API钩取。

180920(记事本WriteFileAPI钩取+调试器)

记事本WriteFileAPI钩取

调试器(Debugger)进行调试的程序
被调试者(Debuggee):被调试的程序
调试器用来确认被调试者是否正确运行,发现程序错误。调试器能够逐一执行被调试者的指令,拥有对寄存器与内存所有访问权限。
调试器无法处理或者不关心的调试事件最终由OS处理。
EXCEPTION_BREAKPOINT异常是必须被处理的。断点对应的汇编指令为INT3,IA-32指令为0xCC。代码调试遇到INT3指令即中断运行,异常事件被传送到调试器。

实验中首先将notepad用od打开,然后进行一次操作,在od中使用api设置断点手法,通过对进程栈的查看找到数据缓冲区的地址,可以进而通过对目标地址内容的操作达到对程序运行的字符串的修改.我们通过这种方法得知了我们应该修改被调试进程内存的哪一部分。

注意我们在设置断点后,起始地址遇到INT3(0xCC)指令就,EIP的值会增加1个字节.(被调试者的地址因此改变了),但OD等调试器不会显示INT3指令,会自动把字节恢复。

为了防止程序执行流陷入死循环,应该脱钩,即修改起始地址处的0xCC为0x6A,取消对API的钩取。
通过DebugActiveProcess()API将调试器附加到该运行的进程上.
WaitForDebugEvent()发生调试事件,就会将相关事件信息设置到其第一个参数的变量,然后立刻返回。
ReadProcessMemory()来获取第一个字节并暂时存储,WriteProcessMemory()来把第一个字节下断点。

脱钩过程不是必须的,可以取消对相关API的调用,也可以调用用户自定义的函数.
Windows OS是一个多线程(multi-thread)操作系统,同一进程 可以同时运行多个线程。
必须在调试器终止前“脱钩”

调试器

WinDbg

OD和IDA pro都是用户态调试器,WinDbg不仅是用户态调试器,还是内核态调试器,主要用于内核模式调试。可以用来直接下载系统文件符号(Symbol),获取系统内部结构体及API的相关信息。还能用来读取、分析windows OS的转储文件。
图形用户界面比较差。

180919(API钩取)

钩取

一、钩取

钩取是一种截取信息,更改程序执行流向、添加新功能的技术。
API(Application Programming Interface,应用程序编程接口)。用户使用系统资源时,通过微软提供的Win32API向系统内核(Kernel)申请。
钩取API可以①自由选择和api调用前后使用钩子代码②查看或操作传入API的参数或API的返回值③取消对API的调用,或更改执行流
XySher
调试器拥有被调试进程的所有权限!
代码注入更难以被杀毒软件检测到。

180918(使用汇编编写注入代码)

使用汇编编写注入代码

一、目标:

使用汇编可以生成比C语言更自由、更灵活的代码。将纯汇编写的ThreadProc()函数注入目标进程。

二、OD汇编

XySher
Ctrl+G能点击这个NewOriginhere,也就是我们的 此处为EIP选项。
XySher
(原来空格打游戏是跳来跳去,总按,现在玩逆向,空格改指令,快乐的1p。)
勾选这个会把输入代码比已有代码段的地方填充为NOP(No Operation)指令,以整体对齐代码(Code Alignment).
XySher
照着书上填完的汇编代码红了一片…
把字符串填了个XySherlock然后为了保持大小填了两个00 按书上对应的灰色区域就是这里的
XySher
XySher
我们需要先点击这个分析视为再分析才有效
XySher
嘿嘿,快乐。

在后面的操作中发现了一个小小的有趣的地方
XySher
在连续打入感叹号的时候会有一条被识别为 and dword ptr ds:[ecx],esp.
这个地方如果开了dep就会将一个部分标记为不可执行,如果没开dep的话可以进行一下利用,输入3的倍数余2的“!”来在这个位置添加一个and dword ptr ds:[ecx],esp指令

180918(代码注入)

代码注入(Code Injection)

一、代码注入

代码注入是一种向目标进程插入独立运行代码并使之运行的技术。一般调用CreateRemoteThread()API以远程线程形式运行插入的代码,所以也被称为线程注入。
这个API在DLL注入的时候曾经用来调用自己写的DLL,它的函数原型如下
HANDLE WINAPI CreateRemoteThread(
in HANDLE hProcess, in LPSECURITY_ATTRIBUTES lpThreadAttributes,
in SIZE_T dwStackSize, in LPTHREAD_START_ROUTINE lpStartAddress,
in LPVOID lpParameter, in DWORD dwCreationFlags,
__out LPDWORD lpThreadId
);
Dll注入处就曾说ThreadProc()和LoadLibrary()都有一个4字节的参数,并返回一个4字节的值。通过CreateRemoteThread()驱使目标进程调用LoadLibrary()函数可以加载指定的DLL文件
代码注入相比DLL注入要更方便,考虑的事情更少,而且几乎不会留下任何痕迹。

二、练习

XySher
跟着书上做的实验notepad的pid是C4
XySher
又一个没跑成的实验==行吧 跟着源码走一遍
XySher
main()函数调用了传入dwPID的InjectCode函数。
XySher
直接注入ThreadProc()进程会导致代码引用地址的内容并不存在于目标进程而出现错误。所以必须同时注入相关字符串以及API地址。(所以本程序中用了THREAD_PARAM结构体接收数据)
在InjectCode()函数中,设置好THREAD_PARAM结构体,然后调用api为data与code分配内存,并将它们注入目标进程,最后调用CreateRemoteThread()API,执行远程线程。

三、代码注入调试练习

XySher
Debugging option是这里的
勾选过后打开
代码注入还是失败,跟着书上找。