解析数据目录表

解析数据目录表
- 导出表
void AnalyzeExportsTabel(char* lpImage)
{
    //1 获取到导出表的结构
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpImage;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + lpImage);
    //1 获取到导出表的数据目录结构
    PIMAGE_DATA_DIRECTORY pExportDir =  &pNt->OptionalHeader.DataDirectory[0];
    //1 导出表的数据目录结构中,有导出表的RVA,咱们需要将其转换为FOA,才能在文件中使用
    DWORD dwExportFOA = RvaToFoa(lpImage, pExportDir->VirtualAddress);
    //1 已经得到了FOA,直接就能够找到导出表的结构
    PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(lpImage + dwExportFOA);
    //typedef struct _IMAGE_EXPORT_DIRECTORY {
    //  DWORD   Characteristics;
    //  DWORD   TimeDateStamp;
    //  WORD    MajorVersion;
    //  WORD    MinorVersion;
    //  DWORD   Name;
    //  DWORD   Base;
    //  DWORD   NumberOfFunctions;
    //  DWORD   NumberOfNames;
    //  DWORD   AddressOfFunctions;     // RVA from base of image
    //  DWORD   AddressOfNames;         // RVA from base of image
    //  DWORD   AddressOfNameOrdinals;  // RVA from base of image
    //} IMAGE_EXPORT_DIRECTORY, * PIMAGE_EXPORT_DIRECTORY;
    DWORD dwBase = pExport->Base;
    //2 得到地址表,名称表,序号表的 FOA
    DWORD EatFoa = RvaToFoa(lpImage,pExport->AddressOfFunctions);
    DWORD EntFoa = RvaToFoa(lpImage, pExport->AddressOfNames);
    DWORD EotFoa = RvaToFoa(lpImage, pExport->AddressOfNameOrdinals);
    //3 得到地址表,名称表,序号表在文件中的位置
    PDWORD  pEat= (PDWORD)(lpImage + EatFoa);
    PDWORD  pEnt = (PDWORD)(lpImage + EntFoa);
    PWORD pEot = (PWORD)(lpImage + EotFoa);
    //4 开始解析
    for (int i = 0; i < pExport->NumberOfFunctions; i++)
    {
        //4.1 无效地址
        if (pEat[i] == 0)
        {
            continue;
        }
        //4.2 有效地址将下标放到序号表中去寻找
        int  j = 0;
        int nSign = FALSE;
        for (; j < pExport->NumberOfNames; j++)
        {
            if (i == pEot[j])
            {
                nSign = TRUE;
                break;
            }
        }
        //4.2.1 找到了,就是有名字的函数
        if (nSign== TRUE)
        {
            //名称表中,存储的是RVA,需要转为FOA
            DWORD dwFunNameFOA =  RvaToFoa(lpImage, pEnt[j]);
            char* pFunName = lpImage + dwFunNameFOA;
            printf("序号:%4x 地址:%x 名称:%s\n", i+ dwBase, pEat[i], pFunName);
        }
        //4.2.2 没有找到,就是没有名字的函数,虚序号
        else
        {
            printf("序号:%4x 地址:%x 名称:NULL\n", i + dwBase, pEat[i]);
        }
    }
}
- 导入表
void AnalyzeImportTabel(char* lpImage,bool bAnalyzeInt)
{
    //1 获取到导入表的结构
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpImage;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + lpImage);
    //1 获取到导入表的数据目录结构
    PIMAGE_DATA_DIRECTORY dwImportDir = &pNt->OptionalHeader.DataDirectory[1];
    //1 导入表的数据目录结构中,有导出表的RVA,咱们需要将其转换为FOA,才能在文件中使用
    DWORD dwImportFOA = RvaToFoa(lpImage, dwImportDir->VirtualAddress);
    //1 已经得到了FOA,直接就能够找到导出表的结构
    PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)(lpImage + dwImportFOA);
    
    //2 开始解析
    while (pImportTable->Name!=0)
    {
        //2.1 先解析DLL的名字
         DWORD dwNameFoa =  RvaToFoa(lpImage,pImportTable->Name);
         char* pDllName = (char*)(dwNameFoa + lpImage);
         printf("DllName:%s\n", pDllName);

         //2.2 解析函数名字,选择用什么去解析
         PIMAGE_THUNK_DATA32 pNameTable = NULL;
        if (bAnalyzeInt == true)
        {
            DWORD Foa  = RvaToFoa(lpImage, pImportTable->OriginalFirstThunk);
            pNameTable = (PIMAGE_THUNK_DATA32)(lpImage + Foa);
        }
        else
        {
            DWORD Foa = RvaToFoa(lpImage, pImportTable->FirstThunk);
            pNameTable = (PIMAGE_THUNK_DATA32)(lpImage + Foa);
        }
        //2.3 开始解析名字
        while (pNameTable->u1.Ordinal!=0)
        {
            //2.3.1 判断最高位是不是1
            if (IMAGE_SNAP_BY_ORDINAL32(pNameTable->u1.Ordinal)==1)
            {
                //只有序号
                printf("  序号:%x,名称:NULL\n", pNameTable->u1.Ordinal&0x7FFFFFFF);
            }
            else
            {
                //既有名字,又有序号
                DWORD dwNameFoa = RvaToFoa(lpImage, pNameTable->u1.AddressOfData);
                PIMAGE_IMPORT_BY_NAME pName  = (PIMAGE_IMPORT_BY_NAME)(dwNameFoa + lpImage);
                printf("  序号:%x,名称:%s\n", pName->Hint,pName->Name);
            }
            pNameTable++;
        }
        printf("----------------------------\n");
        pImportTable++;
    }
}
- 资源表
map<int, const char*> g_mapResourceInfo;
map<const char*, const char*> abc;
void InitResourceInfo()
{
    g_mapResourceInfo[0x1] = "Cursor";
    g_mapResourceInfo[0x2] = "BitMap";
    g_mapResourceInfo[0x3] = "Icon";
    g_mapResourceInfo[0x4] = "Menu";
    g_mapResourceInfo[0x5] = "Dialog";
    g_mapResourceInfo[0x6] = "String Table";
    g_mapResourceInfo[0x7] = "Font Directory";
    g_mapResourceInfo[0x8] = "Font";
    g_mapResourceInfo[0x9] = "Accelerators";
    g_mapResourceInfo[0xA] = "UnFormatted";
    g_mapResourceInfo[0xB] = "Message Table";
    g_mapResourceInfo[0xC] = "Group Cursor";
    g_mapResourceInfo[0xE] = "Group Icon";
    g_mapResourceInfo[0x10] = "Version Information";
}


void AnalyzeResource(char* lpImage)
{
    //1. 找到资源表的结构体
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpImage;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + lpImage);
    PIMAGE_OPTIONAL_HEADER pOption =  &pNt->OptionalHeader;
    //1. 得到了资源表的数据目录
    PIMAGE_DATA_DIRECTORY pResourceDir= &pOption->DataDirectory[2];

    //2. 得到资源表第一层的位置
    DWORD dwResourceFOA =  RvaToFoa(lpImage, pResourceDir->VirtualAddress);
    PIMAGE_RESOURCE_DIRECTORY pFirstDir =(PIMAGE_RESOURCE_DIRECTORY)(dwResourceFOA + lpImage);
    PIMAGE_RESOURCE_DIRECTORY_ENTRY pFirstRes = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pFirstDir + 1);
    //3. 解析资源表
    DWORD dwFirstCount = pFirstDir->NumberOfIdEntries + pFirstDir->NumberOfNamedEntries;
    //3.1 解析第一层
    for (int i = 0; i < dwFirstCount; i++)
    {
        //解析第一层的名称信息

        if (pFirstRes[i].NameIsString == TRUE)
        {
            //以字符串作为标识
            PIMAGE_RESOURCE_DIR_STRING_U pNameInfo = 
            (PIMAGE_RESOURCE_DIR_STRING_U)(pFirstRes[i].NameOffset + (DWORD)pFirstDir);
            WCHAR* pName = new WCHAR[pNameInfo->Length + 1]{0};
            //wcscpy_s(pName, pNameInfo->Length, pNameInfo->NameString);
            for (int m = 0; m < pNameInfo->Length; m++)
            {
                pName[m] = pNameInfo->NameString[m];
            }
            wprintf(L"资源种类标识:%s\n", pName);
        }
        //以数字作为标识
        else
        {
            if (g_mapResourceInfo.count(pFirstRes[i].Id) == 1)
            {
                printf("资源种类标识%s\n", g_mapResourceInfo[pFirstRes[i].Id]);
            }
            else
            {
                printf("资源种类标识%d\n", pFirstRes[i].Id);
            }
        
        }
        //解析第一层的位置信息,从而得到第二层
            
        if (pFirstRes[i].DataIsDirectory == 1)
        {
            //根据偏移得到第二层的位置,以及数组
            PIMAGE_RESOURCE_DIRECTORY pSecondDir =
                (PIMAGE_RESOURCE_DIRECTORY)(pFirstRes[i].OffsetToDirectory + (DWORD)pFirstDir);
            PIMAGE_RESOURCE_DIRECTORY_ENTRY pSecondRes =
                PIMAGE_RESOURCE_DIRECTORY_ENTRY(pSecondDir + 1);
            
            
            //第二层的资源个数
            DWORD dwSecondCount  = 
            pSecondDir->NumberOfIdEntries + pSecondDir->NumberOfNamedEntries;
            for (int j = 0; j < dwSecondCount; j++)
            {
                //解析第二层的名称信息
                if (pSecondRes[j].NameIsString == TRUE)
                {
                    //以字符串作为标识
                    PIMAGE_RESOURCE_DIR_STRING_U pNameInfo =
                        (PIMAGE_RESOURCE_DIR_STRING_U)(pSecondRes[j].NameOffset + (DWORD)pFirstDir);
                    WCHAR* pName = new WCHAR[pNameInfo->Length + 1]{ 0 };
                    //wcscpy_s(pName, pNameInfo->Length + 1, pNameInfo->NameString);
                    for (int m = 0; m < pNameInfo->Length; m++)
                    {
                        pName[m] = pNameInfo->NameString[m];
                    }
                    wprintf(L"   资源标识:%s\n", pName);
                }
                else
                {
                    wprintf(L"   资源标识:%d\n", pSecondRes[j].Id);
                }
                //解析第二层的位置信息
                if (pSecondRes[j].DataIsDirectory == TRUE)
                {
                    //根据偏移得到第三层的位置,以及数组
                    PIMAGE_RESOURCE_DIRECTORY pThirdDir =
                        (PIMAGE_RESOURCE_DIRECTORY)
                        (pSecondRes[j].OffsetToDirectory+ (DWORD)pFirstDir);
                    PIMAGE_RESOURCE_DIRECTORY_ENTRY pThirdRes =
                    (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pThirdDir + 1);

                    //解析第三层,但是不需要循环了
                    PIMAGE_RESOURCE_DATA_ENTRY pData = 
                    (PIMAGE_RESOURCE_DATA_ENTRY)(pThirdRes->OffsetToData + (DWORD)pFirstDir);
                    //pData->OffsetToData 资源起始位置的RVA
                    //pData->Size  资源的大小
                    printf("            资源的起始RVA:%x  资源的大小:%x\n", pData->OffsetToData, pData->Size);
                    //获取到资源的数据了,输出10个字节,用于对比
                    unsigned char* pRes = (unsigned char *)
                        (RvaToFoa(lpImage, pData->OffsetToData) + lpImage);
                    printf("            ");
                    for (size_t m= 0; m < 10; m++)
                    {
                        printf("%x  ", pRes[m]);
                    }
                    printf("\n");
                }
            }
        }
    }
}
- 重定位表
void AnalyzeReloc(char* lpImage)
{
    //1. 找到重定位的结构体
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpImage;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + lpImage);
    PIMAGE_OPTIONAL_HEADER pOption = &pNt->OptionalHeader;
    //1. 得到了重定位的数据目录
    PIMAGE_DATA_DIRECTORY pRelocDir = &pOption->DataDirectory[5];

    //2. 得到重定位表
    PIMAGE_BASE_RELOCATION pReloc = 
        (PIMAGE_BASE_RELOCATION)
    (RvaToFoa(lpImage, pRelocDir->VirtualAddress)+ lpImage);
    //3. 开始解析重定位
    while (pReloc->SizeOfBlock!=0)
    {
        //得到描述每一个位置偏移的数组
        TYPEOFFSET* typeoffset = (TYPEOFFSET*)(pReloc + 1);
        DWORD dwCount = (pReloc->SizeOfBlock - 8) / 2;
        DWORD dwBeginRva =  pReloc->VirtualAddress;
        printf("----------------------------------\n");
        for (int i = 0; i < dwCount; i++)
        {
            if (typeoffset[i].TYPE==3)
            {
                DWORD dwRelocRva = (dwBeginRva + typeoffset[i].OFFSET);
                printf("要重定位的位置RVA:%p\n", dwRelocRva);
                PDWORD pRelocData = (PDWORD)(RvaToFoa(lpImage, dwRelocRva) + lpImage);
                printf("要重定位的数据:%p\n", *pRelocData);
            }
            else
            {
                printf("类型是%d", typeoffset[i].TYPE);
            }

        }
        printf("----------------------------------\n");
        //找到下一个0x1000字节重定位信息
        pReloc = (PIMAGE_BASE_RELOCATION)((char*)pReloc + pReloc->SizeOfBlock);
    }

}
- TLS
// 03_TLS.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>
#pragma comment(linker, "/INCLUDE:__tls_used")
int g_nNum1 = 100;
_declspec(thread) int g_nNum2 = 200;//TLS的全局变量

// TLS回调函数A
void NTAPI t_TlsCallBack_A(PVOID DllHandle, DWORD Reason, PVOID Red) {
    if (DLL_PROCESS_ATTACH == Reason)
    {
        printf("i am a  mimidaima!\r\n");
    }
    if (DLL_THREAD_DETACH == Reason) // 如果线程退出则打印信息
        printf("t_TlsCallBack_A -> ThreadDetach!\r\n");
    return;
}
// TLS回调函数B
void NTAPI t_TlsCallBack_B(PVOID DllHandle, DWORD Reason, PVOID Red) {
    if (DLL_THREAD_DETACH == Reason) // 如果线程退出则打印信息
        printf("t_TlsCallBack_B -> ThreadDetach!\r\n");
    return;
}

/*
* 注册TLS回调函数,".CRT$XLB"的含义是:
* CRT表明使用C RunTime机制
* X表示标识名随机
* L表示TLS callback section
* B其实也可以为B-Y的任意一个字母
*/
#pragma data_seg(".CRT$XLB")
PIMAGE_TLS_CALLBACK p_thread_callback[] = {
    t_TlsCallBack_A,
    t_TlsCallBack_B,
    NULL };
#pragma data_seg()

DWORD WINAPI t_ThreadFun(PVOID pParam) {
    
    printf("%p  ", &g_nNum1);
    printf("%p\n", &g_nNum2);
    return 0;
}

int main()
{
    printf("%p  ", &g_nNum1);
    printf("%p\n", &g_nNum2);
    HANDLE hThread = CreateThread(NULL, 0, t_ThreadFun, NULL, 0, 0);
    WaitForSingleObject(hThread, -1);
    return 0;
}
- 延迟载入
// 04_延迟载入.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//在属性 链接器 输入 选择延迟加载的DLL

#include <iostream>
#include <windows.h>
#include <delayimp.h>
#pragma comment(lib, "Delayimp.lib")

int main()
{
    std::cout << "Hello World!\n";
}
- 读取PE
    //1 打开文件
    HANDLE hFile = CreateFile(
        PATH,
        GENERIC_ALL,//READ,WRITE
        NULL,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );
    //2 获取文件大小
    DWORD dwFileSize = GetFileSize(hFile, NULL);
    //3 申请空间并初始化
    char* buf = new char[dwFileSize] {0};
    //4 读取文件
    DWORD dwRealSize = 0;
    ReadFile(hFile, buf, dwFileSize, &dwRealSize, NULL);
- 判断PE
BOOL IsPE_File(char* lpImage)
{
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpImage;
    if (pDos->e_magic != IMAGE_DOS_SIGNATURE)
    {
        return FALSE;
    }
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + lpImage);

    if (pNt->Signature != IMAGE_NT_SIGNATURE)
    {
        return FALSE;
    }
    return TRUE;
}
- RvaToFoa
DWORD RvaToFoa(char* lpImage, DWORD dwRva)
{
	//1 获取区段表的起始位置
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpImage;
	PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + lpImage);
	PIMAGE_SECTION_HEADER pHeader = IMAGE_FIRST_SECTION(pNt);

	if (dwRva < pNt->OptionalHeader.SizeOfHeaders)
	{
		return dwRva;
	}
	//2 循环判断RVA落在了哪个区段中
	for (int i = 0; i < pNt->FileHeader.NumberOfSections; i++)
	{
		DWORD dwSectionRva = pHeader[i].VirtualAddress;
		DWORD dwSectionEndRva = dwSectionRva + pHeader[i].SizeOfRawData;
		DWORD dwSectionFOA = pHeader[i].PointerToRawData;
		if (dwRva >= dwSectionRva && dwRva <= dwSectionEndRva)
		{
			pHeader[i].VirtualAddress;
			DWORD dwFOA = dwRva - dwSectionRva + dwSectionFOA;
			return dwFOA;
		}
	}
	return -1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值