zoukankan      html  css  js  c++  java
  • 9_山寨系统调用 SystemCallEntry

    思想:

    再次在 GDT 中偷内存 搭建 系统调用需要的 逻辑框架与功能实现;

    基本分解妄想:

    1570290244012

    构建系统调用的代码:

    拷贝到 偷取的内存中:

    1570292102970

    1570292510457

    idt 向量 序号21位置: 8003ee00`0008f120

    各函数的实现:

    注意: systemcallentry() 中

    esp + 0xc 是 3环 的 esp

    3环的 esp 应该是调用 函数的时候的发怒hi地址;所以实际的参数 是 + 4 偏移的位置。

    1570292413023

    测试 效果 代码:

    在 中断表 21 项 构建自己的门;

    1570291369133

    实战:

    1偷取内存

    1.1 侦察可偷取内存

    发现 和前面 差不多 ; 从GDT :0x120 的位置就后面就没有使用了;可以偷取内存。

    1570333829612

    1.2 规划可偷取内存

    给 SysFastCallEntry、ReadMem、AllocMem分别给予 128byte、64byte、64byte的空间;应该够了。

    1570335518313

    2 代码

    2.1 填充代码 到 偷取内存

    #include"pch.h"
    #include <stdio.h>
    #include<stdlib.h>
    #include<Windows.h>

    // release 版本会比较好一点,debug会填充一些空间,release会比较稳定

    DWORD g_iData = 0;//定义一个全局变量,来存储 0 环数据

    DWORD g_Addr[] = {0x8003f120,0x8003f1b0,0x8003f1f0};// 3块 偷取的内存的首地址;分别用来存放 sysfastcallentry、readmem、allocmem的代码

    DWORD *g_ServiceTable =(DWORD*) 0x8003f3c0;//在搞2GB 中 放置我们的山寨 SSDT;根据下标 作为 其服务序号 0 -- ReadMem 、 1 -- AllocMem。


    char *p = NULL;
    int i = 0;
    void SystemCallEntry();
    DWORD  ReadMem();
    DWORD  AllocMem();
    // 已经注册在中断处理中的20项的 函数地址 0环 用作填充函数
    void _declspec(naked) FillData()
    {// 这里是裸函数,所以不会有函数头 push ebp,mov ebp,esp,,和 ret x / sub esp,x 来平衡堆栈;
    // 这样的好处是 我们能控制全部的代码。

    // 通过循环拷贝 code 到 偷取来的区域:
    // 1 .拷贝 systemcallentry() 函数code
    p = (char *)g_Addr[0];
    for (i = 0; i < 128; i++)
    {
    *p = ((char *)SystemCallEntry)[i];
    p++;
    }

    // 2 .拷贝 readmem() 函数code
    p = (char *)g_Addr[1];
    for (i = 0; i < 64; i++)
    {
    *p = ((char *)ReadMem)[i];
    p++;
    }

    // 3. 拷贝AllocMem() 函数 code
    p = (char *)g_Addr[2];
    for (i = 0; i < 64; i++)
    {
    *p = ((char *)AllocMem)[i];
    p++;
    }
    // 初始化 ssdt 表
    g_ServiceTable[0] = 0x8003f1b0;
    g_ServiceTable[1] = 0x8003f1f0;

    // 注册 int 21; 中断向量
    __asm
    {
    // 0x8003f120 --systemcallentry()
    // eq eq 8003f508 8003ee00`0008f120

    mov eax, 0x0008f120;
    mov ds : [0x8003f508], eax;
    mov eax, 0x8003ee00;
    mov ds : [0x8003f50c], eax;

    iretd;//iret 是实地址模式 16位的中断返回
    }


    }
    // SystemCallEntry 函数 实现 注册到 int 21 中去;
    void _declspec(naked) SystemCallEntry()
    {
    __asm
    {

    push 0x30
    pop fs
    sti;//开启中断

    mov ebx,ss:[esp+0xc] // 获取 3环的 esp
    mov ecx,ds:[ebx +4] // 跳过 返回地址 获取参数
    mov ebx,0x8003f3c0  // 山寨 ssdt 地址
    mov eax,ds:[ebx+eax*4]// 获取ssdt[eax] 地址
    call eax

    cli;//关闭中断 怕 pop fs; 和 iretd 之间进行线程切换会崩溃。
    push 0x3b
    pop fs
    iretd;

    }

    }

    // ReadMem 函数 实现
    DWORD _declspec(naked) ReadMem()
    {
    __asm
    {
    mov eax,ds:[ecx] // 直接读取就可以了
    ret
    }

    }
    DWORD g_pAddr;
    // AllocMem 函数 实现
    DWORD _declspec(naked) AllocMem()
    {
    __asm
    {
    push ecx
    push 0
    mov eax,0x8053454C // ExAllocatePool(dd type,dd size);
    call eax
    ret
    }
    }

    void go()
    {
    __asm {
    int 0x20;// 产生中断请求,调用对应中断处理--这里将 int 21 注册systemcallentry(),
    // 并且 将对应的代码拷贝到gdt空闲的区域
    }
    }

    void main()
    {

    if ((DWORD)FillData != 0x401040)// code : there is not same as the past, there some crt func takes the place401000 ~401040
    {
    printf("WRONG ADDR");
            sleep(1000);
    exit(0);
    }
    go();// 产生中断请求,调用对应中断处理;进入0环
    printf("Addr:%p: ", FillData);
    //printf("Data【0x0x8003f500】: %x ", g_iData);
    system("pause");
    }

    测试 山寨 的ssdt 表

    代码:

    // 4_ DIY_sysfastcallentryTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //

    #include "pch.h"
    #include<stdio.h>
    #include<stdlib.h>
    #include<Windows.h>
    DWORD _declspec(nakedreadMem(DWORD Addr)
    {
    __asm
    {
    mov eax, 0
    int 0x21;
    ret;
    }
    }
    DWORD _declspec(nakedAllocMem(DWORD Size)
    {
    __asm
    {
    mov eax, 1
    int 0x21;
    ret;
    }
    }

    int main()
    {
    DWORD A = readMem(0x8003f3c0);
    printf("%p", A);
    DWORD B = AllocMem(0x60);
    printf("%p", B);
    system("pause");
    }

    效果图:

    前面的是读出的数据;

    后面的是申请的内存地址;

    1570348177069


  • 相关阅读:
    《python核心编程第二版》第8章习题
    《python核心编程第二版》第7章习题
    虚拟Ip技术如何实现备机容灾
    LeetCode算法编程连载之五
    GIT使用入门篇(管理自已的代码)
    LeetCode算法编程之连载四(二分法)
    LeetCode算法编程之连载三
    LeetCode算法编程之连载二
    LeetCode算法编程之连载一
    Python 使用flush函数将缓冲区数据立即写磁盘
  • 原文地址:https://www.cnblogs.com/leibso-cy/p/11719180.html
Copyright © 2011-2022 走看看