手动添加节区并且以节区为起始位置的步骤:
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;}