64位栈溢出简单rop与简单例题的复现
首先还是找到关键函数可以看到有read栈溢出漏洞,有system函数,查看字符串,还可以看到”/bin/sh”,既然这样,我们便可以一步到位直接通过rop将/bin/sh装入system函数中getshell。
如何通过rop实现传参呢?64位ELF是通过寄存器存放参数的,所以我们要想办法将/bin/sh放入rdi中并紧接着调用system函数。
那么该如何实现呢?我们假设一下,先通过pop edi将/bin/sh的地址压入edi中,然后再执行ret,并将此时的esp所指向栈空间的值改为system函数的值就可以实现getshell了。
也就是说,我们现在只需要考虑如何能执行pop edi,ret这样的指令了,这时候就需要ropgadget来实现了,通过rop搜索文件中pop edi ret指令的地址,获取这个地址以后,我们就可以通过栈溢出漏洞将返回地址修改为这段指令的地址。
也就是说,我们只需要将ret覆盖位pop edi ret代码的地址,接着覆盖/bin/sh的地址与system函数的地址就可以get shell 了!
开始复现一下例题
找到关键函数与关键的地址以后。尝试编写ex ...
pwn2test
#include<stdio.h>int f(){ char arr[0x20]; read(0,arr,0x100); printf("%s",arr); return 0;}//编译命令 gcc -m32 004.c -o 004 -fno-stack-protector -no-pie// 005 gcc 004.c -o 005 -fno-stack-protector -no-pievoid backdoor(int i){ if (i==40) printf("Pwn it !\n");//system("/bin/sh")}int main(){ f(); return 0;}
这是一道自己编写的pwn2test题目,目的是打印出 “Pwn it !\n” 。先整理一下解题思路,首先通过f函数里的read实现栈溢出,将返回地址覆盖为backdoor的函数地址,但 ...
重学一下汇编
EAX:累加器 AccumulatorEBX:基础寄存器 BaseECX:计数器 CountEDX:数据寄存器 DataESI:源变址寄存器 Source IndexEDI:目的变址寄存器 Destination IndexESP:堆栈指示器 Stack PointerEBP:堆栈基址寄存器 Base Pointer
虽然有这么多名称,实际上除了esp和ebp以外,其他寄存器真正使用时并没有太多区分。
CPU的位宽cpu的位宽暂时没有严格的定义,但是一般从数值上来讲:
cpu的位宽 = 数据总线的位宽 = cpu内部通用寄存器的位宽 = 机器字长
放出一个百度百科对于机器字长的定义供大家理解概念:
机器字长:
机器字长是指计算机进行一次整数运算所能处理的二进制数据的位数,通常也是CPU数据通道的宽度,通常等于CPU的通用寄存器位宽。机器字长会影响机器的运算速度。倘若CPU字长较短,又要运算位数较多的数据,那么必须经过两次或多次运算才能完成 ...
crackme杂记 007
花指令的特征:遇到这种指令,可以立即判断出这是一个花指令,所以花指令较多的话,我们也可以通过搜索代码的方式快速去除如上图,我们已经知道 E8 01 00 00 00 ?? ?? ?? ?? ?? C3 是花指令,所以我们直接搜索这擦混代码一个一个nop就可以了。
易语言中的特征码:想要搜索易语言程序的特征码,最好在程序的开始位置搜索,1.字符串比较函数的特征码: test edx,3执行到这里停住以后,注意观察ECX,EDX寄存器,比骄傲的字符串一定就在这两个寄存器里面,并且我们可以放根据找这个特征码然后往回走去找关键函数的位置。3.这种代码是易语言程序的必经之地,搞这么多jmp是为了模仿PE结构中的IAT也就是导入表,关于什么是导入表,有一个评论说的特别好:
我们知道当程序要调用系统dll时,会用到IAT表
具体是怎么实现的呢,
假设我们程序中某处要用到MessageBoxA,那么这里会有两种形式,一种是先call到一个地址,这个地址中是一个jmp[A],A中存放着数据,数据内容就是我们的MessageBox的入口地址。另一种情况是直接calll到MessageBoxA的入口地址即 ...
crackme杂记 006
c语言中什么函数执行的最早?main函数吗?不是,还有更早执行的函数,比如初始化全局变量的构造函数。我们都知道,od在反汇编一个exe的时候会停止在oep的位置上,那么有比oep还要更早执行的函数吗?有的,比如TLS。
既然tls比ebp都早,那么我们是否可以利用到它呢?比如反调试,如下图代码
#include<iostream>#include<tchar.h>#include"ntdll/ntdll.h"#include<windows.h>DWORD isdebug = 0;//下面这行告诉链接器在PE文件中要创建TLS目录#pragma comment(linker,"/INCLUDE:_tls_used")// 这是PIMAGE_TLS_CALLBACK()函数的原型//其中第一个和第三个参数保留,第二个参数决定函数在那种情况下void NTAPI my_tls_callback(PVOID h, DWORD reason, PVOID pv){ ///共有四个选项DLL_PROCESS_A ...
crackme杂记 004
创建窗口函数: CreatWindowsExA,有时候想要找信息窗口找不到的话可以通过这个函数查找。
花指令:花指令就是类似于jmp,call,ret的指令用来影响我们正常进行反汇编,比如使用花指令的话,IDA就无法正常编译汇编代码。举例:如上图,我们自己写了一个裸函数,可以看到,先写一个jmp Lable,跳转到下面的Lable函数,然后通过 _emit 0e8h 写入一个e8,但是我们知道,e8是call对应的硬编码,所以od就会认为这是一个call ,但是call后面都会跟着一个地址啊,所以od就会将后面的代码理解成call的地址,如下图但是花指令并不能影响程序的运行,因为花指令骗得只是反汇编工具,不如上面的jmp,程序运行的时候该怎么跳就怎么跳,(所以我们设计花指令的思路应该是构造一个恒成立的跳转,然后跳转中间插入无效的代码)我们在调试程序的时候碰到这种情况的话,可以直接将跳转代码的位置与跳转想要跳转的位置之间的代码直接nop掉就好了,所以说,花指令防的住静态调试,但并防不住静态调试。那么花指令远离如上,我们可以一个一个去nop,但是如果花指令特别多怎么办,可以使用插件。但是这 ...
crackme杂记 003
关于dll劫持的一些补充:
如何寻找dll文件,dll文件储存在两个文件夹中,一个是system32文件夹,一个是SysWOW64文件夹,但是前者储存的却是64位程序运行的环境,后者则是32位程序运行的环境。
如何知道想要劫持的dll是否为系统重点保护的,可以查看注册表里的键值,路径如下,里面的dll都是受系统保护的
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\knowndlls
当我们想要加载的是64位的dll,系统却给我们加载了32位的dll怎么办
//判断我们的进程是否为WOW64子系统下的进程 //返回是否成功 if (IsWow64Process((HANDLE)-1, &isWow64Process/*接收返回值,是否执行成功*/)) { //自己判断是否为Wow64下的进程 if (isWow64Process) { GetSystemWow64Directory(tzPath, MAX_PATH); } el ...
crackme杂记 002
实现dll劫持:首先我们需要使用到工具:AheadLIB,这个工具可以帮我们生成dll文件的cpp代码。
什么是dll劫持,就是利用程序运行时会通过搜索名字来运行dll文件的方式,自己生成一个同名的dll文件,并且放在程序的同目录下,从而使程序会使用我们自己生成的dll文件,当然程序仍会使用系统的dll文件,因为我们自己生成的dll文件有系统dll文件的入口,否则我们就需要将系统的dll文件的代码全部生成,那样工作量会非常大,所以dll劫持的意思就是先加载我们的同名dll文件然后继续运行系统的dll文件。
然后开始尝试dll劫持,打开AheadLib工具,将我们想要劫持的dll文件拖入其中,然后直接生成代码这样就生成成功了。然后我们再创建一个dll工程,打开vs,创建一个动态链接库(dll),然后将我们的生成的cpp文件拖入项目文件中,然后再将其在源文件中打开,然后右键我们的项目重新生成,找到dllmain函数,因为dllmain是程序的入口,所以我们可以将我们想要添加的代码放入dllmain函数中,比如我们可以添加一个弹窗来证实我们成功实现dll劫持。
编译链接,找到我们生成的dll ...
crackme杂记
创建一个线程使用 threadproc函数,可以在指定的函数地址创建一个线程,函数内写内容
DWORD WINAPI ThreadProc(_IN_LPVOID lpparameter){ byte byteread=0; while(true) { ReadProcessMemory((HANDLE)-1(进程句柄,-1表示是自己的进程句柄),(LPVOID)004010A9(需要读取的起始地址,od里面查找函数的地址),&byteRead (存放数据的缓存区地址),1(要读取的字节数),NULL(实际读取数存放地址,这里没必要存放,所以直接填NUll)); if(byteread==0x55) { byte wriyeBytes[]={0x90,0x90,0x90,0x90,0x90,0x90}; WriteProcessMemory((HANDLE)-1,(LPVOID)0x004010FD(开始写入的起始地址),writeBytes(写入的东西指向的指针//这里使用指针的话,可以防止别人在逆向调试的时候, ...
160道逆向破解 004
这道题是169道crackme 004
先打开程序,程序如下图。根据同时下载好的txt文档可以知道,如果注册成功会出现朱茵的美图。好了,直接拖入od试一试。还是先试试中文搜索,可以发现有个注册成功字符串。那么我们直接双击进去,往上查找,可以看到一个jnz,但是是往上跳的,继续网上找,看到了一个关键跳 刚好跳过了注册成功,直接nop填充,破解成功。可以看到朱茵的美照。然后再试一试不用中文搜索的方法。
查看一下api函数,emm….数不清有多少个,肯定搞不了了,还是算了,直接注册机吧。由于这个是delphi写的小程序,所以我们直接将其拖入darkde中查看一下时间的地址。
然后去od里面下好断点。然后先查看一下chkcode事件,再头部下好断点以后单步调试,调试中发现了很多可疑的字符串,但是怎么尝试都成功不了。看了一下别人的教程,发现可能是od的问题吧,好多字符串都显示不出来。换一个od再试一次,可以看到黑头sun等等字符串, 然后查看chkcode可以看到下图代码,并且得到注册码: 黑头Sun Bird8dseloffc-012-OKlin,可以看到,如果注册码输入正确则会赋值3E
接下 ...