系统调用与函数地址动态寻找(详解版)

news2024/10/7 12:26:10

双机调试

F9,进入程序领空,搜索所有用户模块的跨模块调用,F2下断点

x64Dbg:F7单步步入,F8单步步过

进入内核的方式:

  1. int 2E(比较早期)
  2. sysenter(x86)
  3. syscall(x64)

进内核的时候,通常会带一个参数(最基本的是系统服务号)

SSDT表:系统描述符表

系统服务号作用:在内核中的SSDT表中进行对照寻找,实际上就是SSDT的索引

在SSDT中寻找对应的内核函数

x86App:

x86 OS:

  1. exe调用OpenProcess


  2. F7跟进去,kernel32.dll进行中转


  3. kernelbase.dll调用ZwOpenProcess(和NTOpenProcess基本没什么区别)


  4. F7,ntdll.dll里,KiFastSystemCall,F7,sysenter进入内核

x64 OS:

  1. exe调用OpenProcess
    在这里插入图片描述

  2. F7跟进去,kernel32.dll进行中转
    在这里插入图片描述

  3. kernelbase.dll调用NtOpenProcess
    在这里插入图片描述

  4. Ntdll.dll调用Wow64,为64位系统下的32位程序实现一个模拟的32位,转发,调用64位的东西
    在这里插入图片描述

x64App

  1. exe调用OpenProcess
    在这里插入图片描述

  2. F7跟进去,kernel32.dll进行中转
    在这里插入图片描述

  3. kernelbase.dll调用ZwOpenProcess(和NTOpenProcessProcess基本没什么区别)
    在这里插入图片描述

  4. ntdll.dll调用syscall/int 2E(这里会做判断)
    在这里插入图片描述

壳:在目标体内加区段,但是我们不能确定目标程序内有没有包含我们需要的头文件或者动态链接库,那么我们就需要自己加载动态链接库,但是我们要加载动态链接库的时候,LoadLibraryAPI 在哪里?我们就要想办法找到API地址

  • TEB(线程环境块)
  • PEB(进程环境块)

描述进程与线程的一些关键成员

  1. 寻找kernel32.dll的地址
  2. 在kernel32.dll的导出表里寻找GetProcAddress

双击调试断下来:

WinDbg输入命令:

  1. ! Process 0 0 (显示简略的系统进程相关信息)
    在这里插入图片描述

    这里的INSTDRV.EXE是我们启动的exe

  2. 复制我们拿到的地址,输入命令:.process /i 0x…(切换到指定进程上下文)

    在这里插入图片描述

    注意这里执行命令之后摁一下F5

  3. ! process(查看进程信息)
    加粗样式

  4. dt _TEB 0x…(拿到线程(TEB)结构)(dt:查看某一个结构)

    在+0x30位置有一个PEB(所属进程的进程环境块信息)
    在这里插入图片描述
    在+0x30的位置有我们需要的PEB信息

  5. dt _PEB 0x…(使用拿到的PEB地址,查看PEB结构)
    在这里插入图片描述

    在+0xC的位置有我们需要的_PEB_LDR_DATA信息

  6. dt _PEB_LDR_DATA ox…(查看_PEB_LDR_DATA结构)
    在这里插入图片描述

  7. dt _LIST_ENTRY查看模块列表
    在这里插入图片描述

    _LIST_ENTRY:有一个Flink(向下的指针),和一个Blink(向上的指针),双向链表

  8. 查看_LDR_DATA_TABLE_ENTRY结构(第一个节点)(向下的指针)
    在这里插入图片描述

这样就找到了进程本身

  1. 继续找下一个节点查看 dt _LDR_DATA_TABLE_ENTRY结构(第一个节点)(向下的指针)ntdll.dll

  2. 继续找,找到了kernel32.dll

  3. 这样我们就可以根据kernek32.dll,遍历导出表,就可以找到GetProcAddress函数地址

动态寻找函数地址

我们根据上述调试过程,我们来写代码实现:

x86:

// 函数地址动态查找.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>

//获取Kernel32地址
DWORD GetKernel32Address();
//获取API地址
DWORD GrkGetProcessAddress();

//函数指针
EXTERN_C typedef HMODULE
(WINAPI* fnLoadLibraryW)(
	_In_ LPCWSTR lpLibFileName
);

EXTERN_C typedef FARPROC
(WINAPI* fnGetProcAddress)(
	_In_ HMODULE hModule,
	_In_ LPCSTR lpProcName
);

EXTERN_C typedef int
(WINAPI* fnMessageBoxW)(
	_In_opt_ HWND hWnd,
	_In_opt_ LPCWSTR lpText,
	_In_opt_ LPCWSTR lpCaption,
	_In_ UINT uType);

EXTERN_C typedef VOID
(WINAPI* fnExitProcess)(
	_In_ UINT uExitCode
);

int main()
{
	fnGetProcAddress pfnGetProcAddress = (fnGetProcAddress)GrkGetProcessAddress();
	HMODULE hKernel32 = (HMODULE)GetKernel32Address();
	fnLoadLibraryW pfnLoadLibraryW = (fnLoadLibraryW)pfnGetProcAddress(hKernel32, "LoadLibraryW");
	HMODULE hUser32 = pfnLoadLibraryW(L"user32.dll");
	fnMessageBoxW pfnMessageBoxW = (fnMessageBoxW)pfnGetProcAddress(hUser32, "MessageBoxW");
	fnExitProcess pfnExitProcess = (fnExitProcess)pfnGetProcAddress(hKernel32,"ExitProcss");
	pfnMessageBoxW(NULL, L"WdIg", L"Msg", NULL);
	system("pause");
	return 0;
}

DWORD GetKernel32Address() {
	DWORD dwKernel32 = 0;
	//NtCurrentTeb方法返回当前线程的线程环境块(TEB)指针
	_TEB *pTeb = NtCurrentTeb();
	//这里就是从线程环境块中找到进程,在线程环境块的+0x30位置
	PDWORD pPeb = (PDWORD)*(PDWORD)((DWORD)pTeb + 0x30);
	//从进程环境块中找到PEB_LDR_DATA信息,在进程环境块中的+0xC位置
	PDWORD pLdr = (PDWORD)*(PDWORD)((DWORD)pPeb + 0xC);
	//这里就是找到_LIST_ENTRY列表
	PDWORD InLoadOrderModuleList = (PDWORD)((DWORD)pLdr + 0xC);
	//这里是找到exe模块
	PDWORD pModuleExe = (PDWORD)*InLoadOrderModuleList;
	//找到Ntdll模块
	PDWORD pModuleNtdll = (PDWORD)*pModuleExe;
	//找到Kernel32模块
	PDWORD pModuleKernel32 = (PDWORD)*pModuleNtdll;
	dwKernel32 = pModuleKernel32[6];
	return dwKernel32;
}

DWORD GrkGetProcessAddress() {
	//这里是我们自己写的函数,得到Kernel32基址
	DWORD dwBase = GetKernel32Address();
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)dwBase;
	PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
	PIMAGE_OPTIONAL_HEADER  pOptionalHeader = &pNtHeaders->OptionalHeader;
	//寻找Kernel32的导出表,以找到我们需要的函数
	PIMAGE_DATA_DIRECTORY pExportDir = &(pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
	PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(dwBase + pExportDir->VirtualAddress);
	//遍历导出表,找到我们需要的函数地址
	DWORD dwFuncCount = pExport->NumberOfFunctions;
	DWORD dwFuncNameCount = pExport->NumberOfNames;
	//导出地址表
	PDWORD pEAT = (PDWORD)(dwBase + pExport->AddressOfFunctions);
	//导出名称表
	PDWORD pENT = (PDWORD)(dwBase + pExport->AddressOfNames);
	//导出序号表
	PWORD pEIT = (PWORD)(dwBase + pExport->AddressOfNameOrdinals);
	for (int i = 0; i < pExport->NumberOfNames; i++)
	{
		if (!pENT[i]) {
			continue;
		}
		char* szFuncName = (char*)(dwBase + (DWORD)pENT[i]);
		DWORD dwOrdinal = 0;
		if (strcmp(szFuncName, "GetProcAddress") == 0) {
			dwOrdinal = pEIT[i];
			DWORD dwFuncAddrOffset = pEAT[dwOrdinal];
			return dwBase + pEAT[dwOrdinal];
		}
	}
	return 0;
}

这里需要格外注意:导出函数名称表是WORD类型的数组

x64:

x64的双机内核调试过程跟x86几乎没有差别

64位由于寻址长度与32位不同,我们将地址长度修改为ULONGLONG即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/963262.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python入门教程 | Python3 列表(List)

Python3 列表 序列是 Python 中最基本的数据结构。 序列中的每个值都有对应的位置值&#xff0c;称之为索引&#xff0c;第一个索引是 0&#xff0c;第二个索引是 1&#xff0c;依此类推。 Python 有 6 个序列的内置类型&#xff0c;但最常见的是列表和元组。 列表都可以进…

CPU彪高排序顺序

简单总结 这类问题分为两大类 代码问题JVM自身问题 我们首先要做的就是先保证代码无bug&#xff0c;排查顺序就是 进程 -> 线程 -> jstack 分析&#xff0c;最后在做JVM的分析。 具体操作 对于Java后台程序CPU使用率高的排查&#xff0c;可以按以下步骤操作&#xf…

解决:burpsuite——Connection refused: no further information

出现该问题的原因是开启了SOCKS proxy&#xff1b;关闭该选项即可正常抓包。 具体操作&#xff1a;

Windows安装配置Rust(附CLion配置与运行)

Windows安装配置Rust&#xff08;附CLion配置与运行&#xff09; 前言一、下载二、安装三、配置标准库&#xff01;&#xff01;&#xff01;四、使用 CLion 运行 rust1、新建rust项目2、配置运行环境3、运行 前言 本文以 windows 安装为例&#xff0c;配置编译器为 minGW&…

flutter plugins插件【一】【FlutterJsonBeanFactory】

1、FlutterJsonBeanFactory 在Setting->Tools->FlutterJsonBeanFactory里边自定义实体类的后缀&#xff0c;默认是entity 复制json到粘贴板&#xff0c;右键自己要存放实体的目录&#xff0c;可以看到JsonToDartBeanAction Class Name是实体名字&#xff0c;会默认加上…

Python入门教程32:计算程序运行的时间

★★★★★博文原创不易&#xff0c;我的博文不需要打赏&#xff0c;也不需要知识付费&#xff0c;可以白嫖学习编程小技巧&#xff0c;喜欢的老铁可以多多帮忙点赞&#xff0c;小红牛在此表示感谢。★★★★★ #我的Python教程 #官方微信公众号&#xff1a;wdPythonPython中可…

stable diffusion实践操作-CLIP

系列文章目录 stable diffusion实践操作 文章目录 系列文章目录前言一、CLIP是什么&#xff1f;1.1 定义&#xff1a;1.2 作用 二、使用步骤2.1 设置使用2.1 跳过层对比图&#xff1a; 三、总结 前言 学习本章之前&#xff0c;先看SD生图原理 stable diffusion实践操作-SD原理…

看看985高校的《数据结构》教材能差到什么程度

网上下了一本教材&#xff0c;看看其内容&#xff0c;不禁开始吃鲸起来。我们的国家的栋梁之材就天天学习这样的教材。 国内外教材但凡多参考也不至于差到如此地步。清华严蔚敏的那本参考一下也不至于写出这么差的教材。 而且用C实现。C被误导&#xff0c;误教&#xff0c;不…

【回溯法-附模板和例题分析】

回溯法 适用于&#xff1a; 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合切割问题&#xff1a;一个字符串按一定规则有几种切割方式子集问题&#xff1a;一个N个数的集合里有多少符合条件的子集排列问题&#xff1a;N个数按一定规则全排列&#xff0c;有几种排列…

LeetCode 面试题 02.08. 环路检测

文章目录 一、题目二、C# 题解 一、题目 给定一个链表&#xff0c;如果它是有环链表&#xff0c;实现一个算法返回环路的开头节点。若环不存在&#xff0c;请返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了…

接口测试系列 —— POSTMAN的简单使用

postman的基本使用 概述 我相信对于postman的介绍&#xff0c;网上一搜肯定很多很多。下面我就不打算跟大家普及postman了。只看应该怎么用postman进行接口测试。好了&#xff0c;下面咱们直接进入正文吧。 环境 postman之前是作为chrome插件形式存在的。后面变成了独立的应…

【zip密码】zip压缩包删除密码方法

Zip压缩包设置设置了密码&#xff0c;想要删除密码&#xff0c;除了将压缩包解压出来之后再将文件压缩为不带密码的压缩文件以外&#xff0c;还有一种删除密码的方法。设置方法如下&#xff1a; 右键点击zip文件&#xff0c;找到打开方式&#xff0c;以Windows资源管理器方式打…

【STM32】学习笔记(OLED)

调试方式 OLED简介 硬件电路 驱动函数 OLED.H #ifndef __OLED_H #define __OLED_Hvoid OLED_Init(void); void OLED_Clear(void); void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char); void OLED_ShowString(uint8_t Line, uint8_t Column, char *String); void OL…

aarch64-linux交叉编译libcurl带zlib和openssl

交叉编译libcurl需要依赖zlib和openssl 需要先用aarch64工具链编译zlib和openssl aarch64-linux环境搭建 下载工具链 gcc用于执行交叉编译 gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnusysroot是交叉版本的库文件集合 sysroot-glibc-linaro-2.25-2019.12-aarch64-lin…

仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法

文章目录 仿gRPC功能实现像调用本地方法一样调用其他服务器方法 简介单体架构微服务架构RPCgPRC gRPC交互逻辑服务端逻辑客户端逻辑示例图 原生实现仿gRPC框架编写客户端方法编写服务端方法综合演示 仿 gRPC功能实现像调用本地方法一样调用其他服务器方法 简介 在介绍gRPC简介…

双网卡/内外网同时使用2023.09.01

1.双网卡 电脑需要两个网卡&#xff1a;两个网口或者是一个有线网卡加一个无线网卡。 查看网关&#xff1a;如下网口接入网线后&#xff0c;电脑连接WIFI&#xff0c;电脑会显示存在两个网卡正在使用&#xff08;电脑存在两个IP地址&#xff09; 查看本地的路由设置 route p…

无涯教程-JavaScript - NEGBINOMDIST函数

NEGBINOMDIST函数取代了Excel 2010中的NEGBINOM.DIST函数。 描述 该函数返回负二项式分布。 NEGBINOMDIST返回在第number_s次成功之前出现number_f次失败的概率,而成功的恒定概率是概率_s。 该函数与二项式分布相似,不同之处在于成功次数是固定的,而试验次数是可变的。像二项…

详细教程:Stegsolve的下载,jdk的下载、安装以及环境的配置

最近在学习隐写术&#xff0c;下载stegsolve 以及使用stegsolve倒腾了很久&#xff0c;避免朋友们和我一样倒腾了很久&#xff0c;希望此文可以帮到刚在学习隐写的朋友们(win7下使用stegsolve) 文章目录 一、下载stegsolve链接二、jdk的下载三、jdk的安装四、配置环境变量五、检…

Java 大厂八股文面试专题-设计模式 工厂方法模式、策略模式、责任链模式

面试专题-设计模式 前言 在平时的开发中&#xff0c;涉及到设计模式的有两块内容&#xff0c;第一个是我们平时使用的框架&#xff08;比如spring、mybatis等&#xff09;&#xff0c;第二个是我们自己开发业务使用的设计模式。 面试官一般比较关心的是你在开发过程中&#xff…

​7.1 项目1 学生通讯录管理:文本文件增删改查(C++版本)(自顶向下设计+断点调试) (A)​

C自学精简教程 目录(必读) 作业目标&#xff1a; 这个作业中&#xff0c;你需要综合运用之前文章中的知识&#xff0c;来解决一个相对完整的应用程序。 作业描述&#xff1a; 1 在这个作业中你需要在文本文件中存储学生通讯录的信息&#xff0c;并在程序启动的时候加载这些…