Next的小站

恶意代码分析 & 逆向工程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "pch.h"
typedef BOOL(WINAPI* WriteFileFuncPtr)(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);

// 全局变量:保存原始WriteFile函数地址(使用正确的函数指针类型)
PROC proc = nullptr;
BOOL WINAPI procnew(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
BOOL Hook_iat(LPCSTR DllName, WriteFileFuncPtr proc, WriteFileFuncPtr procnew);
BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBoxA(NULL, "WriteFile Hook 成功!", "DLL 注入提示", MB_OK | MB_ICONINFORMATION);
proc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile");
Hook_iat("kernel32.dll", (WriteFileFuncPtr)proc, procnew);//提取原本的writefile函数
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Hook_iat("kernel32.dll", procnew, (WriteFileFuncPtr)proc);
break;
}
return TRUE;
}
BOOL WINAPI procnew(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)//编写钩子函数
{
char* newBuffer = new char[nNumberOfBytesToWrite];
memcpy(newBuffer, lpBuffer, nNumberOfBytesToWrite);

for (int k = 0; k < nNumberOfBytesToWrite; k++)
{
if (97 <= newBuffer[k] && newBuffer[k] <= 122)
newBuffer[k] -= 0x20; // 小写转大写
else if (65 <= newBuffer[k] && newBuffer[k] <= 90)
newBuffer[k] += 0x20; // 大写转小写
}
((WriteFileFuncPtr)proc)(hFile, newBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
delete[] newBuffer;
return TRUE;

};
BOOL Hook_iat(LPCSTR DllName, WriteFileFuncPtr proc, WriteFileFuncPtr procnew)
{
HMODULE hMod;
hMod = GetModuleHandleW(NULL);
PBYTE pAddr = (PBYTE)hMod;
IMAGE_NT_HEADERS64 NT = *(PIMAGE_NT_HEADERS64)(pAddr + *(DWORD*)&pAddr[0x3c]);
PIMAGE_IMPORT_DESCRIPTOR Import = (PIMAGE_IMPORT_DESCRIPTOR)(NT.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + pAddr);
for (; Import->Name; Import++)
{
if (!_stricmp((const char*)(pAddr + (DWORD64)Import->Name), DllName))
{
PIMAGE_THUNK_DATA64 IAT = (PIMAGE_THUNK_DATA64)(Import->FirstThunk+ pAddr);
for (; IAT->u1.Function;IAT++)
{
if (IAT->u1.Function == (DWORD64)proc)//找到iat表中write
{
DWORD OldProtect;
VirtualProtect((LPVOID)&IAT->u1.Function, 4, PAGE_EXECUTE_READWRITE, &OldProtect);
IAT->u1.Function = (DWORD64)procnew;
VirtualProtect((LPVOID)&IAT->u1.Function, 4, OldProtect, &OldProtect);
return TRUE;
}
}
}
}
return FALSE;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include<stdio.h>
#include<windows.h>
LPVOID proc;
DWORD int0=0,int3=0xcc;
main() {
EnablePrivilege(SE_DEBUG_NAME, TRUE);
DWORD PID;
scanf_s("%d",&PID);
DebugActiveProcess(PID);
DEBUG_EVENT pe;
while (WaitForDebugEvent(&pe, INFINITE))//等待调试
{
if (pe.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
hook1(&pe);//初次调试设置断点
else if (pe.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
hook2(&pe);//遇到断点修改内容
else if(pe.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT)
break;
ContinueDebugEvent(pe.dwProcessId, pe.dwThreadId, DBG_CONTINUE);
}
}
BOOL hook1(LPDEBUG_EVENT pe)
{
proc = GetProcAddress(GetModuleHandleA("Kernel32.dll"), "WriteFile");
ReadProcessMemory(pe->u.CreateProcessInfo.hProcess, proc, &int0, sizeof(DWORD), NULL);//保存促使值
WriteProcessMemory(pe->u.CreateProcessInfo.hProcess, proc, &int3, sizeof(DWORD), NULL);//设置断点
return TRUE;
}
BOOL hook2(LPDEBUG_EVENT pe)
{
if (pe->u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
{
if (pe->u.Exception.ExceptionRecord.ExceptionAddress == proc)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe->dwProcessId);
HANDLE hThread = OpenThread(
THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_SET_CONTEXT,
FALSE, pe->dwThreadId
);
WriteProcessMemory(hProcess, proc, &int0, sizeof(DWORD), NULL);//恢复断点
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
if(!GetThreadContext(hThread, &ctx))
printf("true%d",GetLastError());//获得寄存器值
printf("\nRCX (hFile): 0x%016llX\n", ctx.Rcx);
printf("RDX (lpBuffer): 0x%016llX\n", ctx.Rdx);
printf("R8 (nNumberOfBytesToWrite): 0x%016llX\n", ctx.R8);//当时那上下文的时候老是拿不到
PBYTE Buffer;
PBYTE pRemoteData = ctx.Rdx;
DWORD pRemoteDataLen = ctx.R8;
Buffer = malloc(pRemoteDataLen + 1);
memset(Buffer, 0, pRemoteDataLen + 1);
if (!ReadProcessMemory(hProcess, (LPVOID)pRemoteData, Buffer, pRemoteDataLen, NULL))
{
printf("read memory wrong!%x",GetLastError());
}
for (int k = 0; k < pRemoteDataLen; k++)
{
if(97<=Buffer[k]&&Buffer[k]<=122)
Buffer[k] -= 0x20;//大写转小写
else if(65<= Buffer[k] && Buffer[k] <= 90)
Buffer[k] += 0x20;
}
WriteProcessMemory(hProcess, (LPVOID)pRemoteData, Buffer, pRemoteDataLen, NULL);
free(Buffer);
ctx.Rip = (DWORD64)proc;
SetThreadContext(hThread, &ctx);//纠正运行地址
ContinueDebugEvent(pe->dwProcessId, pe->dwThreadId, DBG_CONTINUE);
WriteProcessMemory(pe->u.CreateProcessInfo.hProcess, proc, &int3, sizeof(DWORD), NULL);
return TRUE;
}
}
return FALSE;
}
BOOL EnablePrivilege(LPCTSTR Privilege, BOOL enable)
{
LUID Luid;
TOKEN_PRIVILEGES TokenPrivileges;
HANDLE Token;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token);
LookupPrivilegeValueA(NULL, Privilege, &Luid);
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Luid = Luid;
TokenPrivileges.Privileges[0].Attributes = enable;
if(!AdjustTokenPrivileges(Token, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
printf("false%d", GetLastError());
}

这两个实现的效果都是在文件保存后中的英文字母大小写互换

练一下手脱upx+用esp定律加scylla的方法

image-20260413131950179

直接在内存中打开栈顶并下硬件断点4字节的访问断点然后运行(原理就是upx解压相当于一个函数开头会压入栈结尾会输出栈)

image-20260413131925360

再用scylla来dump和修复

依次是dump将内存中的代码复制下来

再是iat autosearch 再到iat表中每个地址对应得是那个dll中得函数

然后get imports来建立函数和dll中导出表得关系

最后fixdunmp重新来填入INT让程序可以运行

image-20260413132600572

顺便解密下这个题

image-20260413132648693

这个头就是解密完了但是upx的效验头其中byte_401171就是主函数

image-20260413132820219

这里是一个常见的花指令由于一定会跳到loc_409030+1去执行后面的

image-20260413132944576

loc_409030位置的E8是call命令就形成干扰直接nop加u c p一下重新编译

image-20260413134258057

image-20260413134327464

找到主函数和地图起点终点得答案

image-20260413134444809

image-20260413134710200

image-20260409082707423

打开程序可以看到逻辑非常简单但是sub_7FF7C68B1320很明显是scanf函数答案又不可能是scuctf{fakeflag}

所以猜测有stl反调

打开TlsDirectory查看回调函数

image-20260409083059688

image-20260409083320531

这里就是两个个反调试

image-20260409083629994

这个是挂钩函数的主函数这里nop掉前面所有反函数后就可以看到

v5的值

image-20260409083907720

unk_14001D178的值

image-20260409083937535

可以看到它将_imp_strcmp指向的ucrtbased_strcmp放在了unk_14001D178上

image-20260409083346785

这个是sub_14001132A(func1)函数的主要逻辑

其中sub_7FF628F611FE()的逻辑就是下面的那张图将unk_14001D178保存的值还给_imp_strcmp指向地方

而下面的就是rc4加密然后再调用__imp_memcmp

image-20260409083434242

image-20260409083456953

这张图是sub_7FF628F61046()的主要逻辑就是将__imp_memcmp指向的值换为sub_14001132A(func1)函数

总结一下这个题的逻辑就是在tls中将j_strcmp钩取然后在主程序使用时调用先还原j_strcmp然后rc4加密再用还原的j_strcmp将密文和下面j_strcmp真正的密钥对比,而scuctf{fakeflag}时密钥。

image-20260409092756473

密文就是unk_7FF628F6D120( 0x98, 0x11, 0xA1, 0x15, 0x1B, 0xFA, 0x99, 0xAB, 0xAF, 0xEA, 0x63, 0xCB, 0xB3, 0x98, 0x52, 0x1C,
0x0D, 0xD5, 0xCE, 0xDA, 0xC4, 0xAF, 0x07, 0xA3, 0x4F, 0xB2, 0x65, 0x99, 0x15, 0x8A, 0xE1, 0x02, 0x4C, 0x3A, 0x1A, 0x69, 0x86, 0xCD, 0x56, 0x9C, 0xCA, 0x2C, 0x40, 0x4A)

由于这个rc4加密将交换改为了异或交换使得它不能用在线工具接的这是解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<stdio.h>
#include<string.h>

void decrypt(char* a1, char* a2, int data_len)
{
unsigned char v1[256];
unsigned char v2[256];
unsigned char temp;

for (int j = 0; j < 256; ++j)
{
v1[j] = j;
int v16 = strlen(a2);
v2[j] = a2[j % v16];
}
unsigned int x1 = 0;
unsigned int x2 = 0;
while (x1 < 256)
{
x2 = (v2[x1] + v1[x1] + x2) % 256;
int v14 = v1[x2] ^ v1[x1];
v1[x1] = v14;
int v15 = v14 ^ v1[x2];
v1[x2] = v15;
v1[x1] ^= v15;
++x1;
}
unsigned int y1 = 0;
unsigned int y2 = 0;
unsigned int y3 = 0;
while (y1 < data_len)
{
y2 = (y2 + 1) % 256;
y3 = (v1[y2] + y3) % 256;
int v14 = v1[y3] ^ v1[y2];
v1[y2] = v14;
int v15 = v14 ^ v1[y3];
v1[y3] = v15;
v1[y2] ^= v15;
int v13 = (v1[y3] + v1[y2]) % 256;
a1[y1++] ^= v1[v13];
}
}

int main()
{
unsigned char a2[] = "scuctf{fakeflag}";
unsigned char a1[45] = {
0x98, 0x11, 0xA1, 0x15, 0x1B, 0xFA, 0x99, 0xAB,
0xAF, 0xEA, 0x63, 0xCB, 0xB3, 0x98, 0x52, 0x1C,
0x0D, 0xD5, 0xCE, 0xDA, 0xC4, 0xAF, 0x07, 0xA3,
0x4F, 0xB2, 0x65, 0x99, 0x15, 0x8A, 0xE1, 0x02,
0x4C, 0x3A, 0x1A, 0x69, 0x86, 0xCD, 0x56, 0x9C,
0xCA, 0x2C, 0x40, 0x4A
};
decrypt(a1, a2, 44);
printf("解密结果:");
for (int i = 0; i < 44; i++) printf("%c", a1[i]);
printf("\n");
return 0;
}

image-20260409152252109

image-20260407010147583

这是主函数

先用findcrypt扫描算法发现有aes和base64编码并回溯找到aes函数位置为sub_4020D0(Block, (int)v22)

image-20260407010221904

接着运行调试时进入sub_402320(ModuleHandleW)发现有int3断点

image-20260407010437363

打开汇编流程图分析

image-20260407010520959

左边的为seh函数右边为主程序

并且在右边发现了注册she函数的汇编

image-20260407010823312

其中seh结构体中loc_4023EF就是主程序中左边的seh函数

image-20260407011015416

这个程序在注册seh后在下面的DebugBreak()会强制出发int3断点然后交给调试器进而反调试我们调试的时候可以选择交给程序自己解决来跳过

在seh中有个函数sub_402450

image-20260407011353264

image-20260407011411898

这其中就是smc代码对每个字节和aSycloversyclov中的字符循环加密然后取反

至于smc的区域肯定在后面可以找到

image-20260407011641548

这个函数中return ((int (*)(void))dword_404000[0])();就是很明显的smc代码

image-20260407011718433

我们用ida脚本来还原

image-20260407011830172

重新编码后可以看到

image-20260407011904719

这是一个对aPvfqyc4ttc2uxr每个字符减一再逆序的函数

image-20260407012102103

解密后可以得到nKnbHsgqD3aNEB91jB3gEzAr+IklQwT1bSs3+bXpeuo=

这很明显是一个base64加密后的结果

结合前面的加密函数中两串连续的字符

image-20260407012354573

image-20260407012404250

推测是aes的cbc模式

image-20260407012435345

解密拿到答案sctf{Ae3_C8c_I28_pKcs79ad4}

image-20260404202151969

这个题打开就知道是ollvm混淆但是用d—810就是去不掉混淆找不到主要逻辑但是我动调拿到了密钥,那个出题人说这个题的密钥生成是根据注册码来的。

image-20260404202516038

可以看到最后v78和v77对比,然而v78是有Src来的然后就直接动调拿答案

image-20260404203007169image-20260404203059298

peloader加载器

1.创建数组来保存pe文件中的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
HANDLE X1(char* x, unsigned char** pbuf)
{
HANDLE X;
DWORD FileSize;
LPDWORD IFFileSize=0;
LPDWORD IFReadFile=0;
X = CreateFileA(x,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
DWORD err= GetLastError();
if (X == INVALID_HANDLE_VALUE)
{
printf("未能打开文件%d", err);
exit(0);
}
FileSize = GetFileSize(X, IFFileSize);
if (IFFileSize == -1)
{
printf("未能得到文件尺寸");
exit(0);
}
*pbuf =(unsigned char *)malloc(sizeof(unsigned char)* FileSize);
ZeroMemory(*pbuf, FileSize);//清零
ReadFile(X, *pbuf, FileSize, IFReadFile, NULL);
if (IFReadFile == -1)
{
printf("未能复制文件");
exit(0);
}
}

2.申请内存将DOS头NT头写入

1
2
3
4
5
6
7
8
9
10
PIMAGE_DOS_HEADER DOS = (PIMAGE_DOS_HEADER)pbuf;
PIMAGE_NT_HEADERS64 NT = (PIMAGE_NT_HEADERS64)(pbuf + DOS->e_lfanew);
DWORD SizeOfImage = NT->OptionalHeader.SizeOfImage;
LPVOID Alloc;
if (NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0)
Alloc = VirtualAlloc(NULL, SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
else
Alloc = VirtualAlloc(NT->OptionalHeader.ImageBase, SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
ZeroMemory(Alloc, SizeOfImage);
CopyMemory(Alloc, pbuf, NT->OptionalHeader.SizeOfHeaders);//申请dos,nt空间

3.将节区循环写入申请内存

1
2
3
4
5
6
7
8
9
10
11
DWORD SectionNumber = NT->FileHeader.NumberOfSections;
for (DWORD n=0; n < SectionNumber; n++)//复制节区
{
PIMAGE_SECTION_HEADER SectionHead = (PIMAGE_SECTION_HEADER)((char*)NT+sizeof(IMAGE_NT_HEADERS64)+ sizeof(IMAGE_SECTION_HEADER)*n);
if (SectionHead->PointerToRawData!=0)//.bss节区(需要初始化)
CopyMemory(SectionHead->VirtualAddress + (PCHAR)Alloc, pbuf + SectionHead->PointerToRawData, SectionHead->SizeOfRawData);
else
{
ZeroMemory(SectionHead->VirtualAddress + (PCHAR)Alloc, SectionHead->Misc.VirtualSize);//清零
}
}

4.加载重定位表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0)
{
PIMAGE_BASE_RELOCATION ReLoc = (PIMAGE_BASE_RELOCATION)(NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (PCHAR)Alloc);
while (ReLoc->SizeOfBlock != 0)
{
PCHAR ReV = ReLoc->VirtualAddress + (PCHAR)Alloc;//每页的虚拟地址
int NumberOfBlock = (ReLoc->SizeOfBlock - 8) / 2;//每页有多少需要修改的值
for (int n = 0; n < NumberOfBlock; n++)
{
PWORD ChangByte = (PWORD)(ReLoc + 1);
char Type = ChangByte[n] >> 12;//获得标志位
if (Type == 10)
{
PDWORD64 Offest = (PDWORD64*)((ChangByte[n] & 0xfff) + ReV);//这页当中需要修改的具体位置
*Offest = *Offest + (ULONGLONG)Alloc - NT->OptionalHeader.ImageBase;//加上基址
}
}
ReLoc = (PIMAGE_SECTION_HEADER)((PCHAR)ReLoc + ReLoc->SizeOfBlock);//下一页
}
}

相关加载重定位表的理解可以看这篇文章:https://blog.csdn.net/Apollon_krj/article/details/77370452

5.填充IAT表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
PIMAGE_IMPORT_DESCRIPTOR IntImport = (PIMAGE_IMPORT_DESCRIPTOR)(NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (PCHAR)Alloc);
while (IntImport->Name!=0)//循环dll库
{
HMODULE DllHandle;
char DllName[50];
strncpy(DllName,IntImport->Name+(PCHAR)Alloc,49);
DllHandle = LoadLibraryA(DllName);
PIMAGE_THUNK_DATA64 INT = IntImport->OriginalFirstThunk + (PCHAR)Alloc;
PIMAGE_THUNK_DATA64 IAT = IntImport->FirstThunk + (PCHAR)Alloc;
while (INT->u1.AddressOfData != 0)//循环dll中每个函数
{
if (INT->u1.Ordinal & IMAGE_ORDINAL_FLAG64)//通过序号查找函数
{
IAT->u1.AddressOfData = GetProcAddress(DllHandle, INT->u1.Ordinal);
}
else//通过名字查找函数
{
PIMAGE_IMPORT_BY_NAME Fcn = (PIMAGE_IMPORT_BY_NAME)(INT->u1.AddressOfData + (PCHAR)Alloc);
IAT->u1.AddressOfData = GetProcAddress(DllHandle, Fcn->Name);//填充IAT表
int l = 1;
}
INT++;
IAT++;
}
IntImport++;
}

相关填充IAT表的理解可以看这篇文章:https://blog.csdn.net/qq_35289660/article/details/107329444

6.修改程序入口

1
2
3
4
5
6
FARPROC EOP = (FARPROC)((LPBYTE)Alloc + NT->OptionalHeader.AddressOfEntryPoint);//修改程序入口点
EOP();

free(pbuf);
free(Alloc);
return 0;

汇总

peloader的加载原理就是将pe文件的内容读取后根据当中的VirtualAddress将内容分配到申请空间里,然后执行。(下面是所有代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
#include <stdbool.h>
#include<winnt.h>

HANDLE X1(char* x, unsigned char** pbuf)
{
HANDLE X;
DWORD FileSize;
LPDWORD IFFileSize=0;
LPDWORD IFReadFile=0;
X = CreateFileA(x,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
DWORD err= GetLastError();
if (X == INVALID_HANDLE_VALUE)
{
printf("未能打开文件%d", err);
exit(0);
}
FileSize = GetFileSize(X, IFFileSize);
if (IFFileSize == -1)
{
printf("未能得到文件尺寸");
exit(0);
}
*pbuf =(unsigned char *)malloc(sizeof(unsigned char)* FileSize);
ZeroMemory(*pbuf, FileSize);
ReadFile(X, *pbuf, FileSize, IFReadFile, NULL);
if (IFReadFile == -1)
{
printf("未能复制文件");
exit(0);
}
}
VOID MAIN1(unsigned char* pbuf) {
printf("这是个64进制文件\n");
Sleep(500);
PIMAGE_DOS_HEADER DOS = (PIMAGE_DOS_HEADER)pbuf;
PIMAGE_NT_HEADERS64 NT = (PIMAGE_NT_HEADERS64)(pbuf + DOS->e_lfanew);
DWORD SizeOfImage = NT->OptionalHeader.SizeOfImage;
LPVOID Alloc;
if (NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0)
Alloc = VirtualAlloc(NULL, SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
else
Alloc = VirtualAlloc(NT->OptionalHeader.ImageBase, SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
ZeroMemory(Alloc, SizeOfImage);
CopyMemory(Alloc, pbuf, NT->OptionalHeader.SizeOfHeaders);//申请dos,nt空间
DWORD SectionNumber = NT->FileHeader.NumberOfSections;
for (DWORD n=0; n < SectionNumber; n++)//复制节区
{
PIMAGE_SECTION_HEADER SectionHead = (PIMAGE_SECTION_HEADER)((char*)NT+sizeof(IMAGE_NT_HEADERS64)+ sizeof(IMAGE_SECTION_HEADER)*n);
if (SectionHead->PointerToRawData!=0)//.bss特殊
CopyMemory(SectionHead->VirtualAddress + (PCHAR)Alloc, pbuf + SectionHead->PointerToRawData, SectionHead->SizeOfRawData);
else//.bss特殊
{
ZeroMemory(SectionHead->VirtualAddress + (PCHAR)Alloc, SectionHead->Misc.VirtualSize);
}
}
if (NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0)
{
PIMAGE_BASE_RELOCATION ReLoc = (PIMAGE_BASE_RELOCATION)(NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (PCHAR)Alloc);
while (ReLoc->SizeOfBlock != 0)
{
PCHAR ReV = ReLoc->VirtualAddress + (PCHAR)Alloc;
int NumberOfBlock = (ReLoc->SizeOfBlock - 8) / 2;
for (int n = 0; n < NumberOfBlock; n++)
{
PWORD ChangByte = (PWORD)(ReLoc + 1);
char Type = ChangByte[n] >> 12;
//PDWORD64 Offest = 0;
if (Type == 10)
{
// 找到目标地址
// 修改目标地址的值:方法是原来的值+偏移
PDWORD64 Offest = (PDWORD64*)((ChangByte[n] & 0xfff) + ReV);
*Offest = *Offest + (ULONGLONG)Alloc - NT->OptionalHeader.ImageBase;
}
}
ReLoc = (PIMAGE_SECTION_HEADER)((PCHAR)ReLoc + ReLoc->SizeOfBlock);
}
}
PIMAGE_IMPORT_DESCRIPTOR IntImport = (PIMAGE_IMPORT_DESCRIPTOR)(NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (PCHAR)Alloc);
while (IntImport->Name!=0)//引入表
{
HMODULE DllHandle;
char DllName[50];
strncpy(DllName,IntImport->Name+(PCHAR)Alloc,49);
DllHandle = LoadLibraryA(DllName);
PIMAGE_THUNK_DATA64 INT = IntImport->OriginalFirstThunk + (PCHAR)Alloc;
PIMAGE_THUNK_DATA64 IAT = IntImport->FirstThunk + (PCHAR)Alloc;
while (INT->u1.AddressOfData != 0)
{
if (INT->u1.Ordinal & IMAGE_ORDINAL_FLAG64)
{
IAT->u1.AddressOfData = GetProcAddress(DllHandle, INT->u1.Ordinal);
}
else
{
PIMAGE_IMPORT_BY_NAME Fcn = (PIMAGE_IMPORT_BY_NAME)(INT->u1.AddressOfData + (PCHAR)Alloc);
IAT->u1.AddressOfData = GetProcAddress(DllHandle, Fcn->Name);
int l = 1;
}
INT++;
IAT++;
}
IntImport++;
}
FARPROC EOP = (FARPROC)((LPBYTE)Alloc + NT->OptionalHeader.AddressOfEntryPoint);
EOP();

free(pbuf);
free(Alloc);
return 0;
}//64文件处理
int main(int argc,char* argv[])
{
unsigned char* pbuf=NULL;
X1(argv[1],&pbuf);
PIMAGE_DOS_HEADER DOS = (PIMAGE_DOS_HEADER)pbuf;
if (*(PWORD)pbuf == 0x5A4D)
printf("这是个PE文件\n");
WORD Magic = *(WORD*)(pbuf + (DOS->e_lfanew + 6 * 4));
if (Magic == 0x20b)
MAIN1(pbuf);
}
0%