首页 > 其他分享 >滴水逆向笔记系列-PE总结3-28.数据目录-29.静态链接库-动态链接库-30.导出表

滴水逆向笔记系列-PE总结3-28.数据目录-29.静态链接库-动态链接库-30.导出表

时间:2024-03-16 10:44:20浏览次数:35  
标签:printf 函数 int 导出 30 28 29 DWORD PIMAGE

第二十八节课 数据目录

1.数据目录是什么

可选PE头最后一个成员,就是数据目录,一共有16个
分别是:导出表的数据目录、导入表的数据目录、资源表的数据目录、异常信息表的数据目录、安全证书表的数据目录、重定位表的数据目录、调试信息表的数据目录、版权所有表的数据目录、全局指针表的数据目录、TLS表的数据目录、加载配置表的数据目录、绑定导入表的数据目录、IAT表的数据目录、延迟导入表的数据目录、COM信息表的数据目录、最后一个保留未使用

2.数据目录的结构

struct _IMAGE_DATA_DIRECTORY{
    DWORD VirtualAddress;  //内存偏移,必须有
	DWORD Size;  //大小,破坏了也不会影响程序运行
};

	char* tableNameArr[16] = {
        "IMAGE_DIRECTORY_ENTRY_EXPORT(导出表)",
        "IMAGE_DIRECTORY_ENTRY_IMPORT(导入表)",
        "IMAGE_DIRECTORY_ENTRY_RESOURCE(资源表)",
        "IMAGE_DIRECTORY_ENTRY_EXCEPTION(异常信息表)",
        "IMAGE_DIRECTORY_ENTRY_SECURITY(安全证书表)",
        "IMAGE_DIRECTORY_ENTRY_BASERELOC(重定位表)",
        "IMAGE_DIRECTORY_ENTRY_DEBUG(调试信息表)",
        "IMAGE_DIRECTORY_ENTRY_COPYRIGHT(版权所有表)",
        "IMAGE_DIRECTORY_ENTRY_GLOBALPTR(全局指针表)",
        "IMAGE_DIRECTORY_ENTRY_TLS(TLS表)",
        "IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(加载配置表)",
        "IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(绑定导入表)",
        "IMAGE_DIRECTORY_ENTRY_IAT(IAT表)",
        "IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT(延迟导入表)",
        "IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR(COM信息表)",
        "保留"
    };

3.数据目录的位置

  • 在节表上面的128个字节(16个数据目录x每个目录8字节)

4.数据目录的作用

记录了16个表的虚拟偏移地址和大小,并不是真正的表,只是记录了表的位置

作业

编写一个函数,打印出数据目录表中的 VirtualAddress 和 Size

LPVOID data_directory_printf(LPVOID pImageBuffer)
{
	PIMAGE_DOS_HEADER pDos_header = NULL;
	PIMAGE_NT_HEADERS pNT_header = NULL;
	PIMAGE_FILE_HEADER pPE_header = NULL;
	PIMAGE_OPTIONAL_HEADER32 pOption_header = NULL;

	//算出ImageBuffer中的dos头nt头pe头节表地址
	pDos_header = (PIMAGE_DOS_HEADER)pImageBuffer;
	pNT_header = (PIMAGE_NT_HEADERS)((DWORD)pDos_header + pDos_header->e_lfanew);
	pPE_header = (PIMAGE_FILE_HEADER)((DWORD)pNT_header + 4);
	pOption_header = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPE_header + IMAGE_SIZEOF_FILE_HEADER);

	for (int i = 0; i < pOption_header->NumberOfRvaAndSizes; i++)
	{
		printf("第%d个表结构\n", i);
		printf("virtualAddress:%x\n", pOption_header->DataDirectory[i].VirtualAddress);
		printf("size:%x\n", pOption_header->DataDirectory[i].Size);
	}

	return pImageBuffer;
}

第二十九课 静态链接库 动态链接库

在一段代码经常需要被我们用到,那么他称之为函数,如果一段代码经常需要被多人用到,我们可以使用以下三种方式,可以避免我们只能把代码复制给别人的麻烦

  1. 静态链接库
  2. 动态链接库
  3. def导出

1.静态链接库的创建

lib文件的编写

image.png
然后我们可以删剩下一个.h头文件和一个.cpp函数
image.png
用一个简单的加减乘除功能演示静态链接库,先在.h头文件写下加减乘除四个函数的声明
image.png
然后再cpp文件写下四个函数的功能实现代码
image.png
然后运行编译,虽然会运行不成功,因为单个lib文件是无法直接运行的,但是lib文件和h文件已经生成了。

lib文件的调用

把文件放入需要调用的代码的同一目录下

资源文件调用

右键资源文件->添加->现有项, 把刚刚拷贝进来的.lib文件添加,添加后资源文件会有显示,然后就可以直接调用静态链接库里的函数了

不使用资源文件调用

#include"MyLib.h"
#pragma comment(lib, "testlib.lib")

2.静态链接库的缺点

  • 使用静态链接生成的可执行文件体积较大,造成浪费
  • 静态链接库在修改lib文件里的函数后需要重新把exe编译
  • 我们常用的printf、memcpy、strcpy等就来自这种静态库

3.动态链接库的创建

int __stdcall Plus(int x,int y){	
	return x+y;
}	
int __stdcall Sub(int x,int y){	
	return x-y;
}	
int __stdcall Mul(int x,int y){	
	return x*y;
}
int __stdcall Div(int x,int y){
	return x/y;
}
extern "C" _declspec(dllexport) __stdcall int Plus (int x,int y);  
extern "C" _declspec(dllexport) __stdcall int Sub (int x,int y);
extern "C" _declspec(dllexport) __stdcall int Mul (int x,int y);
extern "C" _declspec(dllexport) __stdcall int Div (int x,int y);
  • extern:表示这是一个全局函数,可以供各个其他函数调用
  • “C”:指的是此函数按照C语言的方式进行编译、链接。为什么要按照C的方式导出呢?

因为不指定的话,编译器可能会理解成通过C++的方式导出,但是C++允许函数的重载(可以定义相同名字的函数,但参数不同),而假如此时编译器导出后有相同名字的函数,但是此时有一个C程序要使用,但C不支持重载,那么此程序就不知道用哪个函数。①故如果没有指定"C",编译器会自动在导出.dll的时候把当中定义的所有函数名都改了,保证不出现同名函数,这样任何程序使用此动态链接库中函数时就不会出现同名的情况。②如果加上"C",因为C中不能出现同名函数,所以你在动态链接库中定义的函数名是啥就导出啥,不会改名。

  • _declspec(dllexport):指告诉编译器此函数为导出函数,可以供别人使用(一定要写的,固定格式)
  • __stdcall:就是函数的调用约定使用stdcall,我们前面学过,stdcall调用约定的函数会使用内平栈,如果不加VC默认使用cdcall,外平栈。建议如果在Windows下使用动态链接库最后都使用stdcall的调用约定导出.dll

4.动态链接库的使用

方式一:隐式连接

步骤1:将 *.dll *.lib 放到工程目录下面
步骤2:将 #pragma comment(lib,"DLL名.lib") 添加到调用文件中
步骤3:加入函数的声明
extern "C" __declspec(dllimport) __stdcall int Plus (int x,int y);
extern "C" __declspec(dllimport) __stdcall int Sub (int x,int y);
extern "C" __declspec(dllimport) __stdcall int Mul (int x,int y);
extern "C" __declspec(dllimport) __stdcall int Div (int x,int y);
说明:
__declspec(dllimport)告诉编译器此函数为导入函数;

方式二:显示链接

步骤1: //定义函数指针
typedef int (__stdcall *lpPlus)(int,int);
typedef int (__stdcall *lpSub)(int,int);
typedef int (__stdcall *lpMul)(int,int);
typedef int (__stdcall *lpDiv)(int,int);
步骤2: //声明函数指针变量
lpPlus myPlus;
lpSub mySub;
lpMul myMul;
lpDiv myDiv;
步骤3: // //动态加载dll到内存中
HINSTANCE hModule = LoadLibrary("DllDemo.dll");
步骤4: //获取函数地址
myPlus = (lpPlus)GetProcAddress(hModule, "_Plus@8");
mySub = (lpSub)GetProcAddress(hModule, "_Sub@8");
myMul = (lpMul)GetProcAddress(hModule, "_Mul@8");
myDiv = (lpDiv)GetProcAddress(hModule, "_Div@8");
步骤5: //调用函数
int a = myPlus(10,2);
int b = mySub(10,2);
int c = myMul(10,2);
int d = myDiv(10,2);
特别说明:

  • Handle 是代表系统的内核对象,如文件句柄,线程句柄,进程句柄。
  • HMODULE 是代表应用程序载入的模块
  • HINSTANCE 在win32下与HMODULE是相同的东西 Win16 遗留
  • HWND 是窗口句柄

其实就是一个无符号整型,Windows之所以这样设计有2个目的:
1、可读性更好
2、避免在无意中进行运算

方式三:def

和dll一样在动态链接库项目下创建一个cpp和.h头文件,cpp实现代码,头文件声明函数,但是这时候多创建了一个.def文件

EXPORTS	
	
Plus @12
Sub @15 NONAME
Mul @13
Div @16

:::info
Export表示导出
Plus @12:表示Plus函数的导出序号为12
Sub @15 NONAME:表示Sub函数的导出序号为15;NONAME关键字表示Sub函数只有序号,没有名字,这样做就可以将Sub函数名字隐藏(学完导出表后,就可以知道怎么调用这种没有名字的函数)
动态链接库的那种以名字的导出方式也会给函数默认生成一个导出序号;.def导出的方式的序号是自己随便定义的
:::

第三十课 导出表

这节课很多参考这位大佬的文章https://blog.csdn.net/Edimade/article/details/130020286

1.导出表结构

真正的导出表结构如下:
image.png
1、name
指向该导出表文件名字符串的RVA,比如一个DBGHELP.dll的PE文件提供函数,那么这个PE文件的Name指向的字符串为dbghelp.dll
2、base

  • 导出函数起始序号(最小的序号)

比如有序号为14、6、10、8的导出函数,那么Base的值为6
3.NumberOfFunctions

  • 所有导出函数的个数

注意:day35中讲过,这个值是通过导出函数的最大序号 - 最小序号 + 1算出来的;正常来说这个值是多少,那么此PE文件中导出函数的个数就是多少。但是如果使用自定义序号,序号定义时不是连续的,而是中间有空缺的序号,那么此时NumberOfFunctions的值会比实际的定义的导出函数个数多
4.NumberOfNames
以函数名字导出的函数个数:比如以动态链接库的方式导出(注意和只以序号导出函数区分)
如果导出时加了NONAME关键字,那么就不计数
5.AddressOfFunctions
导出函数地址表RVA,即这个地址指向一个表!这个表中记录了此PE文件的所有导出函数的地址
比如使用自定义序号导出函数,即.def的方式导出,定义了序号13、14、16、17、19的导出函数,那么Base的值应为13,那么序号为13的函数相对相对下标就是0,序号14的导出函数相对下标就是1,序号为15的导出函数虽然没有,但是会把位置空出来,只是地址值为NULL,即0x00000000,序号16的导出函数相对下标就是3…以此类推

6.AddressOfNames

  • 导出函数名称表RVA(拉伸后的内存地址偏移,所以要先转成FOA),即这个地址指向一个表,这个表中记录的是导出函数的名称字符串地址!!不是直接存储名称(且此字符串地址也是RVA

注意:

  • 如果函数导出时添加了NONAME,即函数没有名称,那么这个表中就不会出现这个函数名地址
  • 所以AddressOfNames表中元素个数可能比AddressOfFunctions表中元素个数少!(AddressOfFunctions表中不管导出函数有没有名字,都会有地址)
  • 也有可能AddressOfNames表中元素个数比AddressOfFunctions表中元素个数多!因为导出函数时可以让多个不同名字的函数指向同一个函数地址

7.AddressOfNameOrdinals

  • 导出函数序号表RVA,即这个地址指向一个表,表中存的是导出函数的相对序号

2.导出表获取函数地址

按函数名字查找函数地址

image.png
注意:表里的偏移地址都是RVA,需要转成FOA再去计算才能得出FileBuffer中 的地址

按序号找函数地址

给定的序号 - Base = 相对序号i
然后在AddressOfFunctions表找出下标为i的元素值就是函数地址
所以按序号查找和序号表一点关系都没有

RVA转换FOA

RVA需要转换FOA的情况就是内存对齐和文件对齐是不一样的,所以需要对齐
1、如果RVA在文件头里面,那么RVA=FOA,因为文件头在内存和文件中展开都是一样的
2、如果RVA不在文件头里,就需要判断在哪个节里
判断节开始位置到节结束位置 我们的RVA是否在这个范围里面,总共分为三步骤:
第一步:指定节.VirtualAddress <= RVA <= 指定节.VirtualAddress + VirtualSize(当前节内存实际大小)
第二步:差值 = RVA - 指定节.VirtualAddress
第三步:FOA = 指定节.PointerToRawData + 差值

作业

1、输出导出表
2、按名字搜索函数地址
3、按序号搜索函数地址

#pragma warning(disable:4996)
#include<stdio.h>
#include<string.h>
#include<windows.h>
#include<malloc.h>

DWORD Read_File(LPVOID* ppFileBuffer)
{
	FILE* fp = fopen("E:\\7-zip\\7-zip32.dll","rb");
	//FILE* fp = fopen("E:\\notepad1.exe", "rb");
	//FILE* fp = fopen("E:\\IPMSG2007.exe", "rb");
	if (!fp)
	{
		printf("打开文件失败");
		return 0;
	}
	fseek(fp, 0, 2);
	int File_len = ftell(fp);
	fseek(fp, 0, 0);

	*ppFileBuffer = malloc(File_len);
	if (!*ppFileBuffer)
	{
		printf("开辟空间失败");
	}

	size_t t = fread(*ppFileBuffer, File_len, 1, fp);
	if (!t)
	{
		printf("复制失败");
	}
	fclose(fp);
	return File_len;

}

DWORD RVAtoFOA(LPVOID pFileBuffer,DWORD Rva)
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	PIMAGE_SECTION_HEADER NextSectionHeader = NULL;
	DWORD Foa = 0;

	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
	pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
	pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + 20);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);

	if (Rva < pOptionalHeader->SizeOfHeaders)
	{
		printf("Rva在Header里面\n");
		return Rva;
	}

	NextSectionHeader = pSectionHeader + 1;
	for (int i = 1; i < pFileHeader->NumberOfSections; i++, pSectionHeader++, NextSectionHeader++)
	{
		if (Rva >= pSectionHeader->VirtualAddress && Rva < NextSectionHeader->VirtualAddress)
		{
			Foa = pSectionHeader->PointerToRawData + (Rva - pSectionHeader->VirtualAddress);
			return Foa;
		}
	}
	if (Rva >= pSectionHeader->VirtualAddress )
	{
		Foa = pSectionHeader->PointerToRawData + (Rva - pSectionHeader->VirtualAddress);
		return Foa;
	}
	else
	{
		printf("Rav大于sizeofimage!!!\n");
		return 0;
	}

}
VOID PrintfExport(LPVOID pFileBuffer) 
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	PIMAGE_DATA_DIRECTORY pDataDirHeader = NULL;
	PIMAGE_EXPORT_DIRECTORY pExportHeader = NULL;

	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
	pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
	pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + 20);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
	if (pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE) {
		printf("不是有效的MZ标志\n");
	}
	if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
	}

	pDataDirHeader = (PIMAGE_DATA_DIRECTORY)((DWORD)pOptionalHeader + 0x60);
	printf("--------------导出表----------------\n");
	printf("导出表size:%x\n", pDataDirHeader->Size);
	printf("导出表VirtualAddress:%x\n", pDataDirHeader->VirtualAddress);

	pExportHeader = (PIMAGE_EXPORT_DIRECTORY)(RVAtoFOA(pFileBuffer, (DWORD)(pDataDirHeader->VirtualAddress)) + (DWORD)pFileBuffer);
	printf("------------------------------------\n");
	printf("Name:%x\n", pExportHeader->Name);
	printf("Base:%x\n", pExportHeader->Base);
	printf("NumberOfFunctions:%x\n", pExportHeader->NumberOfFunctions);
	printf("NumberOfNames:%x\n", pExportHeader->NumberOfNames);
	printf("-------------AddrOfFun-------------\n");
	PDWORD AddrOfFun = (PDWORD)(RVAtoFOA(pFileBuffer,(DWORD)pExportHeader->AddressOfFunctions) + (DWORD)pFileBuffer);
	for (int i = 0; i < pExportHeader->NumberOfFunctions; i++, AddrOfFun++)
	{
		printf("下标:%d\n", i);
		printf("AddressOfFunctions:%x\n", *AddrOfFun);
	}
	printf("-------------AddrOfNameOrdinal-------------\n");
	PWORD AddrOfNameOrdinal = (PWORD)(RVAtoFOA(pFileBuffer, (DWORD)pExportHeader->AddressOfNameOrdinals) + (DWORD)pFileBuffer);
	for (int t = 0; t < pExportHeader->NumberOfNames; t++, AddrOfNameOrdinal++)
	{
		printf("下标:%d\n", t);
		printf("序号:%x\n", *(PWORD)AddrOfNameOrdinal);
	}
	printf("-------------AddrOfName-------------\n");
	PDWORD AddrOfName = (PDWORD)(RVAtoFOA(pFileBuffer, (DWORD)pExportHeader->AddressOfNames) + (DWORD)pFileBuffer);
	for (int t = 0; t < pExportHeader->NumberOfNames; t++, AddrOfName++)
	{
		char* name = (char*)(RVAtoFOA(pFileBuffer, *(PDWORD)AddrOfName) + (DWORD)pFileBuffer);
		printf("下标:%d\n", t);
		printf("AddressOfName:%x\n", AddrOfName);
		printf("name:%s\n", name);
	}
}

VOID GetAddrByOrdinal(LPVOID pFileBuffer)
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	PIMAGE_DATA_DIRECTORY pDataDirHeader = NULL;
	PIMAGE_EXPORT_DIRECTORY pExportHeader = NULL;

	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
	pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
	pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + 20);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
	pDataDirHeader = (PIMAGE_DATA_DIRECTORY)((DWORD)pOptionalHeader + 0x60);
	pExportHeader = (PIMAGE_EXPORT_DIRECTORY)(RVAtoFOA(pFileBuffer, (DWORD)(pDataDirHeader->VirtualAddress)) + (DWORD)pFileBuffer);

	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
		printf("不是有效的MZ标志\n");
	}
	if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
	}

	int num = 0;
	printf("请输入你要查询的序号:");
	scanf("%d",&num);

	int Addr_num = num - pExportHeader->Base ;
	PDWORD Addr_Fun = (PDWORD)(RVAtoFOA(pFileBuffer, pExportHeader->AddressOfFunctions) + (DWORD)pFileBuffer);
	for (int i = 0; i < Addr_num; i++, Addr_Fun++)
	{
	}
	printf("你查找的函数地址为:%x",*Addr_Fun);

}

VOID GetAddrByName(LPVOID pFileBuffer,const char* str)
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	PIMAGE_DATA_DIRECTORY pDataDirHeader = NULL;
	PIMAGE_EXPORT_DIRECTORY pExportHeader = NULL;
	int flag = 0;
	int t = 0;

	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
	pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
	pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + 20);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
	pDataDirHeader = (PIMAGE_DATA_DIRECTORY)((DWORD)pOptionalHeader + 0x60);
	pExportHeader = (PIMAGE_EXPORT_DIRECTORY)(RVAtoFOA(pFileBuffer, (DWORD)(pDataDirHeader->VirtualAddress)) + (DWORD)pFileBuffer);

	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
		printf("不是有效的MZ标志\n");
	}
	if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
	}
	PDWORD Addr_Name = (PDWORD)(RVAtoFOA(pFileBuffer, pExportHeader->AddressOfNames) + (DWORD)pFileBuffer);
	for (int i = 0; i < pExportHeader->NumberOfFunctions; i++, Addr_Name++)
	{
		char* name = (char*)(RVAtoFOA(pFileBuffer, *Addr_Name) + (DWORD)pFileBuffer);
		if (strcmp(name, str) == 0)
		{
			printf("下标为:%d\n", i);
			flag = i;
			break;
		}
	}
	PWORD Addr_Ordinal = (PWORD)(RVAtoFOA(pFileBuffer, pExportHeader->AddressOfNameOrdinals) + (DWORD)pFileBuffer);
	for (int j = 0; j < flag; j++, Addr_Ordinal++)
	{
	}
	int Ordinal = * (PWORD)Addr_Ordinal;

	PDWORD Addr_Fun = (PDWORD)(RVAtoFOA(pFileBuffer, pExportHeader->AddressOfFunctions) + (DWORD)pFileBuffer);
	for (; t < Ordinal; t++, Addr_Fun++)
	{

	}
	printf("fun下标为:%d\n", t);
	printf("查找的函数地址为:%x\n", *Addr_Fun);
}

标签:printf,函数,int,导出,30,28,29,DWORD,PIMAGE
From: https://www.cnblogs.com/xiaoxin07/p/18076797

相关文章

  • P2824 [HEOI2016/TJOI2016] 排序 与 ABC297_g Range Sort Query 题解
    洛谷题目链接:排序abc题目链接:Atcoder或者洛谷两道差不多的题拿出来说说。本题有双\(\log\)做法,也有单\(\log\)做法,都讲讲。双\(\log\)做法对于第一个题而言,询问最终\(pos\)位置上的数为多少,那么这个问题是否具有单调性?这个是很有意思的点,我们考虑只关注某个数\(x\)......
  • abc281E 滑动窗口前k小的和
    给定数组a[n]以及两个数m与k,求数组a[n]上大小为m的滑动窗口里最小的k个数之和。1<=k<=m<=n<=2e5;1<=a[i]<=1e9套带前缀和的平衡树模板就没有思维难度了。对于模板,如果key不是整型,此时sum就没有意义了,要在自定义类型里重载乘法和加法,无需计算。#include<bits/stdc++.h>using......
  • 代码随想录 第21天 | ● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ●
    leetcode:530.二叉搜索树的最小绝对差-力扣(LeetCode)思路:判断最小绝对差,肯定用中序遍历,双指针一前一后依次判断。classSolution{intresult=Integer.MAX_VALUE;TreeNodepre=null;publicintgetMinimumDifference(TreeNoderoot){if(root==......
  • 洛谷题解 - B3850 [GESP202306 四级] 幸运数
    目录题目描述输入格式输出格式样例#1样例输入#1样例输出#1代码题目描述小明发明了一种“幸运数”。一个正整数,其偶数位不变(个位为第111位,十位为第......
  • 1702967-37-0 PSMA617是一种具有多种功能的化合物
    描述:PSMA617也被称为vipivotidetetraxetan,是一种具有多种功能的化合物。它主要用于制造177Lu-PSMA-617,这是一种抗癌症的放射性分子。PSMA617具有一种小肽,设计用于靶向前列腺特异性膜抗原(PSMA)。PSMA617是一种功能强大的化合物,在治研究领域具有广泛的应用前景。英文名称:PSMA6......
  • 洛谷题单指南-二叉树-P1030 [NOIP2001 普及组] 求先序排列
    原题链接:https://www.luogu.com.cn/problem/P1030题意解读:已知中序、后序,求先序。解题思路:与洛谷题单指南-二叉树-P1827[USACO3.4]美国血统AmericanHeritage非常类似,不在介绍过程,直接给出代码。100分代码:#include<bits/stdc++.h>usingnamespacestd;stringin,post......
  • 波及4300万人!法国官方就业机构数据遭窃
    昨天(3月14日),法国政府机构FranceTravail(前身为PôleEmploi)警告称,有黑客入侵了其系统,并窃取了约4300万人的个人信息。此次遭遇攻击的两家机构分别为负责失业救济的FranceTravail和负责促进残疾人就业的Capemploi。根据2023年1月的数据,法国总人口约为6804万,这意......
  • LY1168 [ 20230325 CQYC省选模拟赛 T3 ] 游戏
    题意给定\(n\)个区间\(l_i,r_i,k_i\)。\(k_i\)表示解锁当前点当且仅当\(l_i\tor_i\)的区间内至少有\(k_i\)个点被解锁。问一共能解锁多少点。Sol直接暴力跑是\(n^2\)的。不难想到优化建图,复杂度:\(O(nk\log)\)这样明显是过不去的。集中注意力。注意到操......
  • 【嵌入式开发】288
    【嵌入式开发】PSC预分频器函数的深入理解在嵌入式系统的定时器(TIM)功能中,PSC(预分频器)是一个关键组件,它负责调整输入时钟信号的频率,以便为定时器提供一个适合的计数速率。对PSC预分频器函数的深入理解,是优化定时器使用、确保精确计时和避免潜在问题的关键。PSC预分频器的......
  • 超低功耗LCD显示段码驱动芯片VKL128 LQFP44 适用于扫地机器人/燃气表-原厂技术支持
    VKL128概述:VKL128是一个点阵式存储映射的LCD驱动器,可支持最大128点(32SEGx4COM)的LCD屏。单片机可通过I2C接口配置显示参数和读写显示数据,可配置4种功耗模式,也可通过关显示和关振荡器进入省电模式。其高抗干扰,低功耗的特性适用于水电气表以及工控仪表类产品。功能特点:•   ......