博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PE学习
阅读量:4705 次
发布时间:2019-06-10

本文共 6644 字,大约阅读时间需要 22 分钟。

直接写一遍PE结构吧  看看记得住不?
MS-DOS
 {
MZ  
`````
e_lfanew
}  64字节
dos-stub 112字节  不定
NT header 
{
Signature  4
IMAGE_FILE_HEADER
{
machine
NumberOfSections
timedatastamp
PointerToSymbolTable
NumberOfSymbols
sizeofOptionalHeader
characteristics
}
OptionalHeader32
{
magic
MajorLinker
MinorLinker
SizeofCode
SizeOfInitializeData
SizeOfUnInirializeData
AddressOfEntryPoint
BaseOfCpde
BaseOfData
ImageBase
SectionAlignment
FileAlignment
Maior操作系统主
操作系统次
用户自定义主
用户次版本
子系统主
子系统次
Win32预留
SizeOfImage 映像装入内存
SizeOfHeader   DOS头+PE头+区块表
校验和
子系统
DllCharactrstics
SizeOfStackReserve 线程保留
委派堆栈··
进程保留
委派堆保留内存
LoaderFlag 调试有关
数据目录项数
DataDirectory 16个
{
IMAGE_DATA_DIRECTORY
{
VirtualAddress  数据块起始RVA
SIZE 数据块长度
}
出 入 资 异       安 重 调 版 全     线 配 绑 导 延 R 预
}
}
}
IMAGE_SECTION_HEADER   数量由   NT_HEADER -> FILE_HEADER->第二元素 NumbersOfSection 指定
{     两排半  
name
union{  padder,
size  }
VitualAddress
SizeOfRawData
PointerToRawData
4个无用信息{  OBJ使用 重定位偏移 + 行号表偏移 + OBJ使用 重定位数目 + 行号数目 }
Characteristics  代码/数据/可读可写 标志    60 00 00 20可读可运行    C0 00 00 20 可读可写  40 00 00 40 可读
}
在后面+一个空的 IMAGE_SECTION_HEADER
最后补齐  200H 倍数

手动添加节区并且以节区为起始位置的步骤:

1)节区大小为    两行半,先添加名称  半排

2)添加节大小,一般0x1000 字节,也就是对齐后长度,注意添加时字节顺序

3)添加节相对虚拟地址,=  上一个节区的相对虚拟地址 + 上一个节对齐后长度(0x1000)

4)添加节在磁盘上的大小,通常为对齐大小0x1000

5)  添加节区在磁盘的偏移值 = 上一个节区的磁盘的偏移值 + 上一个节对齐后长度(0x1000)

6)添加4个无用信息,12字节的都可以是 0 

7)最后4个字节添加  节区的节区属性

8)修改PE文件的节区数量,在OPT header 结构 后面 7 8字节上

9) 修改映像大小  sizeOfImage, OPT header  结构中

10)添加数据 0x1000  在这个区域修改代码即为区段的代码

11)修改PE起始点为 节区代码段(10步骤添加的代码)

文件偏移  =  虚拟地址VA  - ImageBase - (所在块 IMAGE_SECTION_HEADER -> 内存偏移 -  所在块文件偏移)
NT_HEADER->OPTIONAL_HEADER->BaseOfCode                       ->代码段
   数据目录中的各种表

NT_HEADER->OPTIONAL_HEADER->BaseOfData                          -> 数据段

基址重定位  主要用于DLL  因为DLL经常加载到不是预设基址的地址上

typedef struct _IMAGE_BASE_RELOCATION

{

DWORD VirtualAddress; //需重定位数据的起始RVA

DWORD SizeofBlock;    //本结构 8字节 + TypeOffset 总大小

//WORD TypeOffset[1];//不属于 本结构    是需要进行重定位的具体偏移

}

TypeOffset 又定义为  

struct{

WORD Offset:12;   //后12位

WORD Type:4; //前4位

}TypeOffset;

一个重定位区块     的      重定位项的数目  = (SizeOfBlock - IMAGE_SIZEOF_RELOCATION )/ 2    //IMAGE_SIZEOF_RELOCATION也就是8

举个例子:

TypeOffset  = 0x3006

Type  =   0x3

Offset  = 0x006

 VirtualAddress = 0x1000;

重定位的RVA = VirtualAddress + 0x006 = 0x1006

由此  推出需要重定位的数据RVA 为  0x1006

示例代码如下:

typedef struct {	PIMAGE_NT_HEADERS headers;	unsigned char *codeBase;	HMODULE *modules;	int numModules;	int initialized;} MEMORYMODULE, *PMEMORYMODULE;#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader::DataDirectory[idx]void PerformBaseRelocation(PMEMORYMODULE module, DWORD delta) //第二参数为 你把DLL导入到的内存基址 - DLL 文件的 ImageBase{	DWORD i;	unsigned char *codeBase = module->codeBase;	PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC);	if (directory->Size > 0)	{		PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION)(codeBase + directory->VirtualAddress);		for (; relocation->VirtualAddress > 0; )		{			unsigned char *dest = (unsigned char *)(codeBase + relocation->VirtualAddress);			unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION);			for (i=0; i<((relocation->SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++)			{//164				DWORD *patchAddrHL;				int type, offset;				// the upper 4 bits define the type of relocation				type = *relInfo >> 12;   //4bit				// the lower 12 bits define the offset				offset = *relInfo & 0xfff;//12bit								switch (type)				{				case IMAGE_REL_BASED_ABSOLUTE:					// skip relocation					break;				case IMAGE_REL_BASED_HIGHLOW:					// change complete 32 bit address					patchAddrHL = (DWORD *)(dest + offset);					*patchAddrHL += delta;					break;				default:					//printf("Unknown relocation: %d\n", type);					break;				}			}			// advance to next relocation block 有很多个重定位表~~~			relocation = (PIMAGE_BASE_RELOCATION)(((DWORD)relocation) + relocation->SizeOfBlock);		}	}}

EG:

push ebp

mov ebp,esp

push 0xfffffffe

push 0x10002210

假如0x1006 + 0x10000000 对应着 0x10002210  

如果没有加载 首选加载地址  而是加载了0x72AB0000 处,很明显要要对其进行重定位了。

首先计算出他们的差值 为    0x62AB0000    再加上原地址0x10002210 就是重定位后的地址

重定位后的地址  = (加载基址 - ImageBase) + 重定位前的地址

上面的例子为 0x72AB0000 - 0x10000000 + 0x10002210 = 0x72AB2210 

重定位后第四排为

push 0x72AB2210 

TLS 变量

保存在一个.tls区段中

TLS  —— 变量 ——静态模式 主要是指  __declspec (thread) 声明的TLS变量     不能使用在DLL中

   ——动态模式   主要TlsAlloc TlsFree TlsSrtValue TlsGetValue

 ——  回调函数

当我们声明一个tls变量后,系统会自动生成.TLS节

__declspec (thread) int tlsnum = 1;

系统会保证对于每个线程的唯一性。

#include "stdafx.h"#include 
__declspec (thread) int g_num = 0x11111111;__declspec (thread) char g_str[] = "TLS g_num = 0x%p ````\r\n";void NTAPI t_tlscallback_A(PVOID DLLHandle, DWORD Reason, PVOID red){ if (DLL_THREAD_DETACH == Reason) { printf("t_tlscallback_A -> threadDetach ! \r\n"); } return ;}void NTAPI t_tlscallback_B(PVOID DLLHandle, DWORD Reason, PVOID red){ if (DLL_THREAD_DETACH == Reason) { printf("t_tlscallback_B -> threadDetach ! \r\n"); } return ;}#pragma data_seg(".CRT$XLB")PIMAGE_TLS_CALLBACK p_thread_callback[] = { t_tlscallback_A,t_tlscallback_B,NULL};#pragma data_seg()DWORD WINAPI ThreadProc( __in LPVOID lpParameter ){ printf("ThreadProc first printf\n"); printf(g_str,g_num); g_num = 0x22222222; printf("ThreadProc second printf\n"); printf(g_str,g_num); return 0;}int _tmain(int argc, _TCHAR* argv[]){ printf("_tmain ``````````````````````````\n"); CreateThread(NULL,0,ThreadProc,NULL,0,0); Sleep(1000); printf("\r\n"); CreateThread(NULL,0,ThreadProc,NULL,0,0); system("pause"); return 0;}/*_tmain ``````````````````````````ThreadProc first printfTLS g_num = 0x11111111 ````ThreadProc second printfTLS g_num = 0x22222222 ````t_tlscallback_A -> threadDetach !t_tlscallback_B -> threadDetach !ThreadProc first printfTLS g_num = 0x11111111 ````ThreadProc second printfTLS g_num = 0x22222222 ````t_tlscallback_A -> threadDetach !t_tlscallback_B -> threadDetach !*/

另一个作用  就是在程序main函数运行前 进行操作

#include "stdafx.h"#include 
#pragma comment(linker,"/include:__tls_used")//这句很重要void NTAPI t_tlscallback_A(PVOID DLLHandle, DWORD Reason, PVOID red){ if (DLL_PROCESS_ATTACH == Reason) { MessageBox(NULL,_T("hi,this is tls callback"),_T("title"),MB_OK); } PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL); PIMAGE_NT_HEADERS32 pNt = (PIMAGE_NT_HEADERS32)((DWORD)pDos+(DWORD)pDos->e_lfanew); BYTE* OEP = (BYTE*)(pNt->OptionalHeader.AddressOfEntryPoint + (DWORD)pDos); for (unsigned int i=0;i<200;i++) { if (OEP[i] == 0xcc) { MessageBox(NULL,_T("检测到CC断点"),_T("检测到CC断点"),MB_OK); } } return ;}#pragma data_seg(".CRT$XLB")PIMAGE_TLS_CALLBACK p_thread_callback[] = { t_tlscallback_A,NULL};#pragma data_seg()int _tmain(int argc, _TCHAR* argv[]){ printf("MAIN START\N"); system("pause"); return 0;}

转载于:https://www.cnblogs.com/zcc1414/p/3982445.html

你可能感兴趣的文章
selenium的句柄
查看>>
实验四附加实验 项目互评
查看>>
利用GPU实现大规模动画角色的渲染
查看>>
POJ---2524 Ubiquitous Religions[简单并查集]
查看>>
[SCOI2005]王室联邦
查看>>
CodeForces - 1016D Vasya And The Matrix
查看>>
angularjs 中的iframe 标签 ng-src 路径
查看>>
cURL error 60: SSL certificate problem...
查看>>
05-图3. 六度空间 (30)
查看>>
MongoDB 基本使用
查看>>
.NET框架 - NETCORE部署IIS
查看>>
采购申请审批策略增强
查看>>
算法笔记_223:打印回型嵌套(Java)
查看>>
机器学习 -- 文本挖掘
查看>>
某单位排队形,开始排成3路纵队,末尾多出2个人,后改称5路纵队,末尾又多出3个人 ,后改成7路纵队,正好没有余数,求单位总人数...
查看>>
第五次作业
查看>>
微信小程序-canvas画布
查看>>
centos7 install fastdfs nginx
查看>>
GNG1106 – Fundamentals of Engineering Computation
查看>>
lumen 单元测试
查看>>