mirror of
https://github.com/d35ha/CallObfuscator
synced 2026-06-08 13:42:37 +00:00
1022 lines
35 KiB
C++
1022 lines
35 KiB
C++
#include <vector>
|
|
#include "xPE/xPE.h"
|
|
|
|
struct ObfuscateByName
|
|
{
|
|
LPCSTR szOldApi;
|
|
LPCSTR szNewApi;
|
|
PIMAGE_THUNK_DATA lpOThunk;
|
|
DWORD dwFThunkRva;
|
|
};
|
|
|
|
struct ReplaceApi
|
|
{
|
|
LPCSTR szOldApi;
|
|
LPCSTR szNewApi;
|
|
};
|
|
|
|
INT main(INT argc, CHAR** argv){
|
|
|
|
if (argc >= 4){
|
|
|
|
LPCSTR szInFileName = argv[1];
|
|
LPCSTR szOutFileName = argv[2];
|
|
|
|
std::vector<ObfuscateByName> ObfuscateByNameArr;
|
|
std::vector<ReplaceApi> ReplaceApiArr;
|
|
|
|
do
|
|
{
|
|
argc--;
|
|
LPCSTR szOldApi = argv[argc];
|
|
LPCSTR szNewApi = strstr(szOldApi, ",");
|
|
if (!szNewApi)
|
|
{
|
|
Utils::Printf::Fail("Invalid apis array");
|
|
return FALSE;
|
|
};
|
|
*(PBYTE)szNewApi = 0;
|
|
szNewApi += 1;
|
|
|
|
BYTE bReplaceApiElement[sizeof(ReplaceApi)] = { 0 };
|
|
ReplaceApi* lpReplaceApiElement = (ReplaceApi*)bReplaceApiElement;
|
|
lpReplaceApiElement->szOldApi = szOldApi;
|
|
lpReplaceApiElement->szNewApi = szNewApi;
|
|
ReplaceApiArr.push_back(*lpReplaceApiElement);
|
|
|
|
} while (argc != 3);
|
|
|
|
BYTE bPeFileInfo[sizeof(RAW_FILE_INFO)] = { 0 };
|
|
if (!Load::File::Load(
|
|
szInFileName,
|
|
(PRAW_FILE_INFO)bPeFileInfo,
|
|
sizeof(bPeFileInfo)
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Cannot load this file %s", szInFileName);
|
|
return FALSE;
|
|
};
|
|
PRAW_FILE_INFO lpPeFileInfo = (PRAW_FILE_INFO)bPeFileInfo;
|
|
|
|
DWORD PeArch = x32;
|
|
if (!Load::PE::GetArch(lpPeFileInfo, &PeArch))
|
|
{
|
|
Utils::Printf::Fail("Cannot get the archeticture");
|
|
return FALSE;
|
|
};
|
|
|
|
#if defined(_M_X64) || defined(__amd64__)
|
|
if (PeArch == x32)
|
|
{
|
|
Utils::Printf::Fail("Use the x32 binary to handle this PE");
|
|
return FALSE;
|
|
};
|
|
#else
|
|
if (PeArch == x64)
|
|
{
|
|
Utils::Printf::Fail("Use the x64 binary to handle this PE");
|
|
return FALSE;
|
|
};
|
|
#endif
|
|
|
|
PIMAGE_NT_HEADERS lpNtHeader = NULL;
|
|
if (!Load::PE::GetNtHeader(
|
|
lpPeFileInfo,
|
|
&lpNtHeader
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Unable to get the NT header from the PE");
|
|
return FALSE;
|
|
};
|
|
|
|
if (!Utils::IsValidReadPtr(
|
|
lpPeFileInfo->lpDataBuffer,
|
|
lpNtHeader->OptionalHeader.SizeOfHeaders
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Invalid headers size");
|
|
return FALSE;
|
|
};
|
|
|
|
DWORD dwImportBaseOffset = 0;
|
|
DWORD dwImportSize = 0;
|
|
if (!Load::PE::GetDirectoryInfo(
|
|
lpNtHeader,
|
|
IMAGE_DIRECTORY_ENTRY_IMPORT,
|
|
&dwImportBaseOffset,
|
|
&dwImportSize,
|
|
FALSE
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Unable to get the IMAGE_DIRECTORY_ENTRY_IMPORT table information");
|
|
return FALSE;
|
|
};
|
|
|
|
PIMAGE_IMPORT_DESCRIPTOR lpImportData = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)lpPeFileInfo->lpDataBuffer + dwImportBaseOffset);
|
|
while (lpImportData->Name != NULL)
|
|
{
|
|
if (!Utils::IsValidReadPtr(
|
|
lpImportData,
|
|
sizeof(IMAGE_IMPORT_DESCRIPTOR)
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Invalid import directory");
|
|
return FALSE;
|
|
};
|
|
|
|
DWORD dwLibNameOffset = lpImportData->Name;
|
|
if (!Utils::RvaToOffset(lpNtHeader, dwLibNameOffset, &dwLibNameOffset))
|
|
{
|
|
Utils::Printf::Fail("Unable to get the imported library name");
|
|
return FALSE;
|
|
};
|
|
PCHAR szDllName = (PCHAR)((DWORD_PTR)lpPeFileInfo->lpDataBuffer + dwLibNameOffset);
|
|
|
|
if (!Utils::IsValidReadPtr(
|
|
szDllName,
|
|
sizeof(".dll")
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Invalid library name");
|
|
return FALSE;
|
|
};
|
|
|
|
DWORD dwOriginalThunk = lpImportData->OriginalFirstThunk;
|
|
|
|
if (!dwOriginalThunk)
|
|
{
|
|
Utils::Printf::Fail("Invalid Import table");
|
|
return FALSE;
|
|
};
|
|
|
|
if (!Utils::RvaToOffset(lpNtHeader, dwOriginalThunk, &dwOriginalThunk))
|
|
{
|
|
Utils::Printf::Fail("Unable to get the IMAGE_THUNK_DATA array entry");
|
|
return FALSE;
|
|
};
|
|
PIMAGE_THUNK_DATA dwCThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)lpPeFileInfo->lpDataBuffer + dwOriginalThunk);
|
|
DWORD dwFirstThunk = lpImportData->FirstThunk;
|
|
|
|
while (dwCThunk->u1.AddressOfData)
|
|
{
|
|
if (!Utils::IsValidReadPtr(
|
|
dwCThunk,
|
|
sizeof(IMAGE_THUNK_DATA)
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Invalid import directory");
|
|
return FALSE;
|
|
};
|
|
|
|
if (IMAGE_SNAP_BY_ORDINAL(dwCThunk->u1.Ordinal)) {
|
|
|
|
WORD wOrdinal = IMAGE_ORDINAL(dwCThunk->u1.Ordinal);
|
|
Utils::Printf::Info("An import by ordinal %d found at %s, this cannot be handled for now", wOrdinal, szDllName);
|
|
}
|
|
else
|
|
{
|
|
DWORD lpApiImportOffset = (DWORD)dwCThunk->u1.AddressOfData;
|
|
if (!Utils::RvaToOffset(lpNtHeader, lpApiImportOffset, &lpApiImportOffset))
|
|
{
|
|
Utils::Printf::Fail("Unable to get the IMAGE_IMPORT_BY_NAME structure pointer");
|
|
return FALSE;
|
|
};
|
|
PIMAGE_IMPORT_BY_NAME lpApiImport = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)lpPeFileInfo->lpDataBuffer + lpApiImportOffset);
|
|
|
|
if (!Utils::IsValidReadPtr(
|
|
lpApiImport,
|
|
sizeof(IMAGE_IMPORT_BY_NAME)
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Invalid import directory");
|
|
return FALSE;
|
|
};
|
|
|
|
for (auto const& ReplaceApiElement : ReplaceApiArr) {
|
|
if (!strcmp(ReplaceApiElement.szOldApi, (PCHAR)lpApiImport->Name))
|
|
{
|
|
BYTE bObfuscateByNameElement[sizeof(ObfuscateByName)] = { 0 };
|
|
ObfuscateByName* lpObfuscateByNameElement = (ObfuscateByName*)bObfuscateByNameElement;
|
|
lpObfuscateByNameElement->dwFThunkRva = dwFirstThunk;
|
|
lpObfuscateByNameElement->szOldApi = ReplaceApiElement.szOldApi;
|
|
lpObfuscateByNameElement->szNewApi = ReplaceApiElement.szNewApi;
|
|
lpObfuscateByNameElement->lpOThunk = dwCThunk;
|
|
ObfuscateByNameArr.push_back(*lpObfuscateByNameElement);
|
|
|
|
PIMAGE_SECTION_HEADER lpHeaderSection = IMAGE_FIRST_SECTION(lpNtHeader);
|
|
for (DWORD dwSecIndex = 0; dwSecIndex < lpNtHeader->FileHeader.NumberOfSections; dwSecIndex++) {
|
|
if (dwFirstThunk >= lpHeaderSection[dwSecIndex].VirtualAddress &&
|
|
dwFirstThunk < lpHeaderSection[dwSecIndex].VirtualAddress + lpHeaderSection[dwSecIndex].Misc.VirtualSize)
|
|
{
|
|
lpHeaderSection[dwSecIndex].Characteristics |= IMAGE_SCN_MEM_WRITE;
|
|
break;
|
|
};
|
|
};
|
|
break;
|
|
};
|
|
};
|
|
};
|
|
dwOriginalThunk += sizeof(IMAGE_THUNK_DATA);
|
|
dwFirstThunk += sizeof(IMAGE_THUNK_DATA);
|
|
dwCThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)lpPeFileInfo->lpDataBuffer + dwOriginalThunk);
|
|
};
|
|
|
|
lpImportData++;
|
|
};
|
|
|
|
if (!ObfuscateByNameArr.size()) return TRUE;
|
|
DWORD dwEntryOffset = lpNtHeader->OptionalHeader.AddressOfEntryPoint;
|
|
if (!Utils::RvaToOffset(lpNtHeader, dwEntryOffset, &dwEntryOffset))
|
|
{
|
|
Utils::Printf::Fail("Unable to get the entry point offset");
|
|
return FALSE;
|
|
};
|
|
LPVOID lpEntry = (LPVOID)((DWORD_PTR)lpPeFileInfo->lpDataBuffer + dwEntryOffset);
|
|
|
|
BYTE bOriginalBytes[0x5] = { 0 };
|
|
if (!Utils::SafeMemoryCopy(
|
|
(LPVOID)bOriginalBytes,
|
|
sizeof(bOriginalBytes),
|
|
lpEntry,
|
|
sizeof(bOriginalBytes)
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Unable to read the original 5 bytes from the entry point");
|
|
return FALSE;
|
|
};
|
|
|
|
BYTE bShellcode[] =
|
|
{
|
|
#if defined(_M_X64) || defined(__amd64__)
|
|
/*
|
|
0: 41 5f pop r15
|
|
2: 49 83 ef 05 sub r15,0x5
|
|
6: 48 83 ec 28 sub rsp,0x28
|
|
a: 6a 60 push 0x60
|
|
c: 58 pop rax
|
|
d: 65 48 8b 10 mov rdx,QWORD PTR gs:[rax]
|
|
11: 48 8b 52 18 mov rdx,QWORD PTR [rdx+0x18]
|
|
15: 48 8b 52 10 mov rdx,QWORD PTR [rdx+0x10]
|
|
19: 52 push rdx
|
|
1a: 5e pop rsi
|
|
1b: 48 ad lods rax,QWORD PTR ds:[rsi]
|
|
1d: 48 96 xchg rsi,rax
|
|
1f: 48 ad lods rax,QWORD PTR ds:[rsi]
|
|
21: 48 8b 68 30 mov rbp,QWORD PTR [rax+0x30]
|
|
25: 8b 45 3c mov eax,DWORD PTR [rbp+0x3c]
|
|
28: 8b 9c 05 88 00 00 00 mov ebx,DWORD PTR [rbp+rax*1+0x88]
|
|
2f: 48 01 eb add rbx,rbp
|
|
32: 8b 73 20 mov esi,DWORD PTR [rbx+0x20]
|
|
35: 48 01 ee add rsi,rbp
|
|
38: 48 31 c9 xor rcx,rcx
|
|
3b: 48 ff c1 inc rcx
|
|
3e: ad lods eax,DWORD PTR ds:[rsi]
|
|
3f: 48 01 e8 add rax,rbp
|
|
42: 81 38 47 65 74 50 cmp DWORD PTR [rax],0x50746547
|
|
48: 75 f1 jne 0x3b
|
|
4a: 81 78 04 72 6f 63 41 cmp DWORD PTR [rax+0x4],0x41636f72
|
|
51: 75 e8 jne 0x3b
|
|
53: 81 78 08 64 64 72 65 cmp DWORD PTR [rax+0x8],0x65726464
|
|
5a: 75 df jne 0x3b
|
|
5c: 8b 73 24 mov esi,DWORD PTR [rbx+0x24]
|
|
5f: 48 01 ee add rsi,rbp
|
|
62: 66 8b 0c 4e mov cx,WORD PTR [rsi+rcx*2]
|
|
66: 48 ff c9 dec rcx
|
|
69: 8b 73 1c mov esi,DWORD PTR [rbx+0x1c]
|
|
6c: 48 01 ee add rsi,rbp
|
|
6f: 8b 3c 8e mov edi,DWORD PTR [rsi+rcx*4]
|
|
72: 48 01 ef add rdi,rbp
|
|
75: 52 push rdx
|
|
76: 5e pop rsi
|
|
77: 48 8b 6e 30 mov rbp,QWORD PTR [rsi+0x30]
|
|
7b: 56 push rsi
|
|
7c: 41 5e pop r14
|
|
7e: eb 4f jmp 0xcf
|
|
80: 5b pop rbx
|
|
81: 48 31 d2 xor rdx,rdx
|
|
84: 38 13 cmp BYTE PTR [rbx],dl
|
|
86: 74 33 je 0xbb
|
|
88: 48 8b 36 mov rsi,QWORD PTR [rsi]
|
|
8b: 48 8b 4e 30 mov rcx,QWORD PTR [rsi+0x30]
|
|
8f: 48 85 c9 test rcx,rcx
|
|
92: 74 3a je 0xce
|
|
94: 53 push rbx
|
|
95: 5a pop rdx
|
|
96: ff d7 call rdi
|
|
98: 48 85 c0 test rax,rax
|
|
9b: 74 eb je 0x88
|
|
9d: 48 31 d2 xor rdx,rdx
|
|
a0: 48 ff c3 inc rbx
|
|
a3: 38 13 cmp BYTE PTR [rbx],dl
|
|
a5: 75 f9 jne 0xa0
|
|
a7: 48 ff c3 inc rbx
|
|
aa: 8b 13 mov edx,DWORD PTR [rbx]
|
|
ac: 48 01 ea add rdx,rbp
|
|
af: 48 89 02 mov QWORD PTR [rdx],rax
|
|
b2: 41 56 push r14
|
|
b4: 5e pop rsi
|
|
b5: 48 83 c3 04 add rbx,0x4
|
|
b9: eb c6 jmp 0x81
|
|
bb: 48 83 c4 28 add rsp,0x28
|
|
bf: 41 c7 07 ff ff ff ff mov DWORD PTR [r15],<first_original_four_bytes>
|
|
c6: 41 c6 47 04 ff mov BYTE PTR [r15+0x4],<fifth_original_byte>
|
|
cb: 41 ff e7 jmp r15
|
|
ce: cc int3
|
|
cf: e8 ac ff ff ff call 0x80
|
|
*/
|
|
|
|
0x41, 0x5F, 0x49, 0x83, 0xEF, 0x05, 0x48, 0x83, 0xEC, 0x28, 0x6A, 0x60, 0x58, 0x65, 0x48, 0x8B, 0x10, 0x48, 0x8B, 0x52, 0x18,
|
|
0x48, 0x8B, 0x52, 0x10, 0x52, 0x5E, 0x48, 0xAD, 0x48, 0x96, 0x48, 0xAD, 0x48, 0x8B, 0x68, 0x30, 0x8B, 0x45, 0x3C, 0x8B, 0x9C,
|
|
0x05, 0x88, 0x00, 0x00, 0x00, 0x48, 0x01, 0xEB, 0x8B, 0x73, 0x20, 0x48, 0x01, 0xEE, 0x48, 0x31, 0xC9, 0x48, 0xFF, 0xC1, 0xAD,
|
|
0x48, 0x01, 0xE8, 0x81, 0x38, 0x47, 0x65, 0x74, 0x50, 0x75, 0xF1, 0x81, 0x78, 0x04, 0x72, 0x6F, 0x63, 0x41, 0x75, 0xE8, 0x81,
|
|
0x78, 0x08, 0x64, 0x64, 0x72, 0x65, 0x75, 0xDF, 0x8B, 0x73, 0x24, 0x48, 0x01, 0xEE, 0x66, 0x8B, 0x0C, 0x4E, 0x48, 0xFF, 0xC9,
|
|
0x8B, 0x73, 0x1C, 0x48, 0x01, 0xEE, 0x8B, 0x3C, 0x8E, 0x48, 0x01, 0xEF, 0x52, 0x5E, 0x48, 0x8B, 0x6E, 0x30, 0x56, 0x41, 0x5E,
|
|
0xEB, 0x4F, 0x5B, 0x48, 0x31, 0xD2, 0x38, 0x13, 0x74, 0x33, 0x48, 0x8B, 0x36, 0x48, 0x8B, 0x4E, 0x30, 0x48, 0x85, 0xC9, 0x74,
|
|
0x3A, 0x53, 0x5A, 0xFF, 0xD7, 0x48, 0x85, 0xC0, 0x74, 0xEB, 0x48, 0x31, 0xD2, 0x48, 0xFF, 0xC3, 0x38, 0x13, 0x75, 0xF9, 0x48,
|
|
0xFF, 0xC3, 0x8B, 0x13, 0x48, 0x01, 0xEA, 0x48, 0x89, 0x02, 0x41, 0x56, 0x5E, 0x48, 0x83, 0xC3, 0x04, 0xEB, 0xC6, 0x48, 0x83,
|
|
0xC4, 0x28, 0x41, 0xC7, 0x07,
|
|
bOriginalBytes[0], bOriginalBytes[1],
|
|
bOriginalBytes[2], bOriginalBytes[3],
|
|
0x41, 0xC6, 0x47, 0x04, bOriginalBytes[4],
|
|
0x41, 0xFF, 0xE7, 0xCC, 0xE8, 0xAC, 0xFF, 0xFF, 0xFF
|
|
#else
|
|
/*
|
|
0: 6a 30 push 0x30
|
|
2: 58 pop eax
|
|
3: 64 8b 10 mov edx,DWORD PTR fs:[eax]
|
|
6: 8b 52 0c mov edx,DWORD PTR [edx+0xc]
|
|
9: 8b 52 0c mov edx,DWORD PTR [edx+0xc]
|
|
c: 89 d6 mov esi,edx
|
|
e: ad lods eax,DWORD PTR ds:[esi]
|
|
f: 96 xchg esi,eax
|
|
10: ad lods eax,DWORD PTR ds:[esi]
|
|
11: 8b 68 18 mov ebp,DWORD PTR [eax+0x18]
|
|
14: 8b 45 3c mov eax,DWORD PTR [ebp+0x3c]
|
|
17: 8b 5c 05 78 mov ebx,DWORD PTR [ebp+eax*1+0x78]
|
|
1b: 01 eb add ebx,ebp
|
|
1d: 8b 73 20 mov esi,DWORD PTR [ebx+0x20]
|
|
20: 01 ee add esi,ebp
|
|
22: 31 c9 xor ecx,ecx
|
|
24: 41 inc ecx
|
|
25: ad lods eax,DWORD PTR ds:[esi]
|
|
26: 01 e8 add eax,ebp
|
|
28: 81 38 47 65 74 50 cmp DWORD PTR [eax],0x50746547
|
|
2e: 75 f4 jne 0x24
|
|
30: 81 78 04 72 6f 63 41 cmp DWORD PTR [eax+0x4],0x41636f72
|
|
37: 75 eb jne 0x24
|
|
39: 81 78 08 64 64 72 65 cmp DWORD PTR [eax+0x8],0x65726464
|
|
40: 75 e2 jne 0x24
|
|
42: 8b 73 24 mov esi,DWORD PTR [ebx+0x24]
|
|
45: 01 ee add esi,ebp
|
|
47: 66 8b 0c 4e mov cx,WORD PTR [esi+ecx*2]
|
|
4b: 49 dec ecx
|
|
4c: 8b 73 1c mov esi,DWORD PTR [ebx+0x1c]
|
|
4f: 01 ee add esi,ebp
|
|
51: 8b 3c 8e mov edi,DWORD PTR [esi+ecx*4]
|
|
54: 01 ef add edi,ebp
|
|
56: 89 d6 mov esi,edx
|
|
58: 8b 6e 18 mov ebp,DWORD PTR [esi+0x18]
|
|
5b: 56 push esi
|
|
5c: eb 41 jmp 0x9f
|
|
5e: 5b pop ebx
|
|
5f: 31 d2 xor edx,edx
|
|
61: 38 13 cmp BYTE PTR [ebx],dl
|
|
63: 74 27 je 0x8c
|
|
65: 8b 36 mov esi,DWORD PTR [esi]
|
|
67: 8b 4e 18 mov ecx,DWORD PTR [esi+0x18]
|
|
6a: 85 c9 test ecx,ecx
|
|
6c: 74 30 je 0x9e
|
|
6e: 53 push ebx
|
|
6f: 51 push ecx
|
|
70: ff d7 call edi
|
|
72: 85 c0 test eax,eax
|
|
74: 74 ef je 0x65
|
|
76: 31 d2 xor edx,edx
|
|
78: 43 inc ebx
|
|
79: 38 13 cmp BYTE PTR [ebx],dl
|
|
7b: 75 fb jne 0x78
|
|
7d: 43 inc ebx
|
|
7e: 8b 13 mov edx,DWORD PTR [ebx]
|
|
80: 01 ea add edx,ebp
|
|
82: 89 02 mov DWORD PTR [edx],eax
|
|
84: 8b 34 24 mov esi,DWORD PTR [esp]
|
|
87: 83 c3 04 add ebx,0x4
|
|
8a: eb d3 jmp 0x5f
|
|
8c: 5e pop esi
|
|
8d: 5d pop ebp
|
|
8e: 83 ed 05 sub ebp,0x5
|
|
91: c7 45 00 ff ff ff ff mov DWORD PTR [ebp+0x0],<first_original_four_bytes>
|
|
98: c6 45 04 ff mov BYTE PTR [ebp+0x4],<fifth_original_byte>
|
|
9c: ff e5 jmp ebp
|
|
9e: cc int3
|
|
9f: e8 ba ff ff ff call 0x5e
|
|
*/
|
|
|
|
0x6A, 0x30, 0x58, 0x64, 0x8B, 0x10, 0x8B, 0x52, 0x0C, 0x8B, 0x52, 0x0C, 0x89, 0xD6, 0xAD, 0x96, 0xAD, 0x8B, 0x68, 0x18, 0x8B,
|
|
0x45, 0x3C, 0x8B, 0x5C, 0x05, 0x78, 0x01, 0xEB, 0x8B, 0x73, 0x20, 0x01, 0xEE, 0x31, 0xC9, 0x41, 0xAD, 0x01, 0xE8, 0x81, 0x38,
|
|
0x47, 0x65, 0x74, 0x50, 0x75, 0xF4, 0x81, 0x78, 0x04, 0x72, 0x6F, 0x63, 0x41, 0x75, 0xEB, 0x81, 0x78, 0x08, 0x64, 0x64, 0x72,
|
|
0x65, 0x75, 0xE2, 0x8B, 0x73, 0x24, 0x01, 0xEE, 0x66, 0x8B, 0x0C, 0x4E, 0x49, 0x8B, 0x73, 0x1C, 0x01, 0xEE, 0x8B, 0x3C, 0x8E,
|
|
0x01, 0xEF, 0x89, 0xD6, 0x8B, 0x6E, 0x18, 0x56, 0xEB, 0x41, 0x5B, 0x31, 0xD2, 0x38, 0x13, 0x74, 0x27, 0x8B, 0x36, 0x8B, 0x4E,
|
|
0x18, 0x85, 0xC9, 0x74, 0x30, 0x53, 0x51, 0xFF, 0xD7, 0x85, 0xC0, 0x74, 0xEF, 0x31, 0xD2, 0x43, 0x38, 0x13, 0x75, 0xFB, 0x43,
|
|
0x8B, 0x13, 0x01, 0xEA, 0x89, 0x02, 0x8B, 0x34, 0x24, 0x83, 0xC3, 0x04, 0xEB, 0xD3, 0x5E, 0x5D, 0x83, 0xED, 0x05, 0xC7, 0x45,
|
|
0x00,
|
|
bOriginalBytes[0], bOriginalBytes[1],
|
|
bOriginalBytes[2], bOriginalBytes[3],
|
|
0xC6, 0x45, 0x04, bOriginalBytes[4],
|
|
0xFF, 0xE5, 0xCC, 0xE8, 0xBA, 0xFF, 0xFF, 0xFF
|
|
#endif
|
|
};
|
|
DWORD dwPaddedShellcodeSize = sizeof(bShellcode);
|
|
|
|
for (auto const& ObfuscateByNameElement : ObfuscateByNameArr)
|
|
{
|
|
dwPaddedShellcodeSize += (DWORD)strlen(ObfuscateByNameElement.szOldApi) + 1;
|
|
dwPaddedShellcodeSize += (DWORD)sizeof(ObfuscateByNameElement.dwFThunkRva);
|
|
};
|
|
dwPaddedShellcodeSize++;
|
|
|
|
DWORD dwNewApisArrayOffset = dwPaddedShellcodeSize;
|
|
|
|
for (auto const& ObfuscateByNameElement : ObfuscateByNameArr)
|
|
{
|
|
if (strlen(ObfuscateByNameElement.szNewApi) > strlen(ObfuscateByNameElement.szOldApi))
|
|
{
|
|
dwPaddedShellcodeSize += (DWORD)sizeof(WORD);
|
|
dwPaddedShellcodeSize += (DWORD)strlen(ObfuscateByNameElement.szNewApi) + 1;
|
|
};
|
|
};
|
|
|
|
LPVOID lpShellCode = NULL;
|
|
if (!(lpShellCode = VirtualAlloc(
|
|
NULL,
|
|
dwPaddedShellcodeSize,
|
|
MEM_COMMIT | MEM_RESERVE,
|
|
PAGE_READWRITE
|
|
)))
|
|
{
|
|
Utils::Reportf::ApiError("VirtualAlloc", "Cannot allocate the size of %d, for the shellcode", dwPaddedShellcodeSize);
|
|
return FALSE;
|
|
};
|
|
|
|
CopyMemory(
|
|
lpShellCode,
|
|
bShellcode,
|
|
sizeof(bShellcode)
|
|
);
|
|
|
|
if (lpNtHeader->FileHeader.PointerToSymbolTable)
|
|
{
|
|
PIMAGE_SYMBOL lpCOFFSymbol = (PIMAGE_SYMBOL)((DWORD_PTR)lpPeFileInfo->lpDataBuffer +
|
|
lpNtHeader->FileHeader.PointerToSymbolTable);
|
|
LPVOID lpCOFFString = (LPVOID)((DWORD_PTR)lpCOFFSymbol + lpNtHeader->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL));
|
|
|
|
if (!Utils::IsValidWritePtr(
|
|
lpCOFFSymbol,
|
|
*(PDWORD)lpCOFFString + lpNtHeader->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL)
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Invalid COFF symbol table");
|
|
return FALSE;
|
|
};
|
|
|
|
ZeroMemory(
|
|
lpCOFFSymbol,
|
|
*(PDWORD)lpCOFFString + lpNtHeader->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL)
|
|
);
|
|
|
|
lpNtHeader->FileHeader.PointerToSymbolTable = 0;
|
|
lpNtHeader->FileHeader.NumberOfSymbols = 0;
|
|
};
|
|
|
|
BOOL IsDebugExists = FALSE;
|
|
if (!Load::PE::IsDirExists(lpNtHeader, IMAGE_DIRECTORY_ENTRY_DEBUG, &IsDebugExists))
|
|
{
|
|
Utils::Printf::Fail("Cannot check if IMAGE_DIRECTORY_ENTRY_DEBUG table exists");
|
|
return FALSE;
|
|
};
|
|
if (IsDebugExists)
|
|
{
|
|
DWORD dwDebugBaseOffset = 0;
|
|
DWORD dwDebugSize = 0;
|
|
if (!Load::PE::GetDirectoryInfo(
|
|
lpNtHeader,
|
|
IMAGE_DIRECTORY_ENTRY_DEBUG,
|
|
&dwDebugBaseOffset,
|
|
&dwDebugSize,
|
|
FALSE
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Unable to get the IMAGE_DIRECTORY_ENTRY_DEBUG table information");
|
|
return FALSE;
|
|
};
|
|
PIMAGE_DEBUG_DIRECTORY lpDebugData = (PIMAGE_DEBUG_DIRECTORY)((DWORD_PTR)lpPeFileInfo->lpDataBuffer + dwDebugBaseOffset);
|
|
|
|
if (!Utils::IsValidWritePtr(
|
|
lpDebugData,
|
|
sizeof(IMAGE_DEBUG_DIRECTORY)
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Invalid debug directory");
|
|
return FALSE;
|
|
};
|
|
|
|
ZeroMemory(
|
|
lpDebugData,
|
|
sizeof(IMAGE_DEBUG_DIRECTORY)
|
|
);
|
|
|
|
GET_DIRECTORY_ENTRY(lpNtHeader, IMAGE_DIRECTORY_ENTRY_DEBUG) = 0;
|
|
GET_DIRECTORY_SIZE(lpNtHeader, IMAGE_DIRECTORY_ENTRY_DEBUG) = 0;
|
|
};
|
|
|
|
DWORD dwShellcodeOffset = 0;
|
|
DWORD dwRawSizeNeeded = 0;
|
|
|
|
PIMAGE_SECTION_HEADER lpExecutableSection = NULL;
|
|
PIMAGE_SECTION_HEADER lpHeaderSection = IMAGE_FIRST_SECTION(lpNtHeader);
|
|
for (DWORD dwSecIndex = 0; dwSecIndex < lpNtHeader->FileHeader.NumberOfSections; dwSecIndex++) {
|
|
if (!dwShellcodeOffset && (lpHeaderSection[dwSecIndex].Characteristics & IMAGE_SCN_MEM_EXECUTE))
|
|
{
|
|
lpExecutableSection = &lpHeaderSection[dwSecIndex];
|
|
lpHeaderSection[dwSecIndex].Characteristics |= IMAGE_SCN_MEM_WRITE;
|
|
DWORD dwRealVirtualSize = 0;
|
|
if (dwSecIndex == lpNtHeader->FileHeader.NumberOfSections - 1)
|
|
{
|
|
dwRealVirtualSize = lpNtHeader->OptionalHeader.SizeOfImage -
|
|
lpHeaderSection[dwSecIndex].VirtualAddress;
|
|
}
|
|
else
|
|
{
|
|
dwRealVirtualSize = lpHeaderSection[dwSecIndex + 1].VirtualAddress -
|
|
lpHeaderSection[dwSecIndex].VirtualAddress;
|
|
};
|
|
if (dwRealVirtualSize - lpHeaderSection[dwSecIndex].Misc.VirtualSize < dwPaddedShellcodeSize)
|
|
{
|
|
if (dwSecIndex != lpNtHeader->FileHeader.NumberOfSections - 1) continue;
|
|
while (dwRealVirtualSize - lpHeaderSection[dwSecIndex].Misc.VirtualSize < dwPaddedShellcodeSize)
|
|
{
|
|
lpNtHeader->OptionalHeader.SizeOfImage += lpNtHeader->OptionalHeader.SectionAlignment;
|
|
dwRealVirtualSize = lpNtHeader->OptionalHeader.SizeOfImage -
|
|
lpHeaderSection[dwSecIndex].VirtualAddress;
|
|
};
|
|
};
|
|
|
|
dwShellcodeOffset = lpHeaderSection[dwSecIndex].PointerToRawData + lpHeaderSection[dwSecIndex].Misc.VirtualSize;
|
|
if (lpHeaderSection[dwSecIndex].SizeOfRawData - lpHeaderSection[dwSecIndex].Misc.VirtualSize >= dwPaddedShellcodeSize)
|
|
{
|
|
lpHeaderSection[dwSecIndex].Misc.VirtualSize += dwPaddedShellcodeSize;
|
|
dwPaddedShellcodeSize += lpHeaderSection[dwSecIndex].SizeOfRawData - lpHeaderSection[dwSecIndex].Misc.VirtualSize;
|
|
dwRawSizeNeeded = 0;
|
|
break;
|
|
};
|
|
|
|
lpHeaderSection[dwSecIndex].Misc.VirtualSize += dwPaddedShellcodeSize;
|
|
|
|
DWORD dwVirtualRawSpace = 0;
|
|
if ((dwVirtualRawSpace = Utils::AlignUp(
|
|
dwShellcodeOffset,
|
|
lpNtHeader->OptionalHeader.FileAlignment
|
|
) - dwShellcodeOffset) < dwPaddedShellcodeSize)
|
|
{
|
|
dwRawSizeNeeded = Utils::AlignUp(
|
|
dwPaddedShellcodeSize - dwVirtualRawSpace,
|
|
lpNtHeader->OptionalHeader.FileAlignment
|
|
);
|
|
}
|
|
else dwRawSizeNeeded = 0;
|
|
dwPaddedShellcodeSize += dwRawSizeNeeded + lpHeaderSection[dwSecIndex].SizeOfRawData - lpHeaderSection[dwSecIndex].Misc.VirtualSize;
|
|
|
|
BOOL IsSecurityExists = FALSE;
|
|
if (!Load::PE::IsDirExists(lpNtHeader, IMAGE_DIRECTORY_ENTRY_SECURITY, &IsSecurityExists))
|
|
{
|
|
Utils::Printf::Fail("Cannot check if IMAGE_DIRECTORY_ENTRY_SECURITY table exists");
|
|
return FALSE;
|
|
};
|
|
if (IsSecurityExists)
|
|
{
|
|
DWORD dwSecurityBaseOffset = 0;
|
|
DWORD dwSecuritySize = 0;
|
|
if (!Load::PE::GetDirectoryInfo(
|
|
lpNtHeader,
|
|
IMAGE_DIRECTORY_ENTRY_SECURITY,
|
|
&dwSecurityBaseOffset,
|
|
&dwSecuritySize,
|
|
FALSE
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Unable to get the IMAGE_DIRECTORY_ENTRY_SECURITY table information");
|
|
return FALSE;
|
|
};
|
|
if (dwSecurityBaseOffset >= lpHeaderSection[dwSecIndex].PointerToRawData + lpHeaderSection[dwSecIndex].SizeOfRawData)
|
|
{
|
|
GET_DIRECTORY_ENTRY(lpNtHeader, IMAGE_DIRECTORY_ENTRY_SECURITY) += dwRawSizeNeeded;
|
|
};
|
|
};
|
|
|
|
lpHeaderSection[dwSecIndex].SizeOfRawData += dwRawSizeNeeded;
|
|
lpNtHeader->OptionalHeader.SizeOfCode += dwRawSizeNeeded;
|
|
#if ! (defined(_M_X64) || defined(__amd64__))
|
|
if (lpNtHeader->OptionalHeader.BaseOfData > lpNtHeader->OptionalHeader.BaseOfCode)
|
|
{
|
|
lpNtHeader->OptionalHeader.BaseOfData += dwRawSizeNeeded;
|
|
};
|
|
#endif
|
|
}
|
|
else if (dwRawSizeNeeded && lpHeaderSection[dwSecIndex].PointerToRawData
|
|
) lpHeaderSection[dwSecIndex].PointerToRawData += dwRawSizeNeeded;
|
|
};
|
|
|
|
if (!lpExecutableSection)
|
|
{
|
|
Utils::Printf::Fail("Unable to get any executable section IMAGE_SECTION_HEADER structure");
|
|
return FALSE;
|
|
};
|
|
|
|
DWORD dwShellcodeRVA = 0;
|
|
DWORD dwShellcodeSize = sizeof(bShellcode);
|
|
if (!dwShellcodeOffset)
|
|
{
|
|
PIMAGE_SECTION_HEADER lpImageSectionHeader = IMAGE_FIRST_SECTION(lpNtHeader);
|
|
PIMAGE_SECTION_HEADER lpNewSectionHeader = &lpImageSectionHeader[lpNtHeader->FileHeader.NumberOfSections];
|
|
|
|
if ((DWORD_PTR)lpNewSectionHeader + sizeof(IMAGE_SECTION_HEADER) - (DWORD_PTR)lpPeFileInfo->lpDataBuffer
|
|
> lpNtHeader->OptionalHeader.SizeOfHeaders)
|
|
{
|
|
Utils::Printf::Fail("No enough space at the headers for the new section");
|
|
return FALSE;
|
|
};
|
|
|
|
ZeroMemory(
|
|
lpNewSectionHeader,
|
|
sizeof(IMAGE_SECTION_HEADER)
|
|
);
|
|
|
|
lpNewSectionHeader->VirtualAddress = lpNtHeader->OptionalHeader.SizeOfImage;
|
|
lpNewSectionHeader->PointerToRawData = lpImageSectionHeader[lpNtHeader->FileHeader.NumberOfSections - 1].PointerToRawData
|
|
+ lpImageSectionHeader[lpNtHeader->FileHeader.NumberOfSections - 1].SizeOfRawData;
|
|
lpNewSectionHeader->SizeOfRawData = Utils::AlignUp(
|
|
dwPaddedShellcodeSize,
|
|
lpNtHeader->OptionalHeader.FileAlignment
|
|
);
|
|
lpNewSectionHeader->Misc.VirtualSize = dwPaddedShellcodeSize;
|
|
lpNewSectionHeader->Characteristics =
|
|
IMAGE_SCN_MEM_EXECUTE |
|
|
IMAGE_SCN_MEM_READ;
|
|
|
|
dwPaddedShellcodeSize = Utils::AlignUp(
|
|
lpNewSectionHeader->Misc.VirtualSize,
|
|
lpNtHeader->OptionalHeader.SectionAlignment
|
|
);
|
|
dwShellcodeOffset = lpNewSectionHeader->PointerToRawData;
|
|
dwShellcodeRVA = lpNewSectionHeader->VirtualAddress;
|
|
|
|
lpNtHeader->FileHeader.NumberOfSections++;
|
|
lpNtHeader->OptionalHeader.SizeOfImage += dwPaddedShellcodeSize;
|
|
|
|
BOOL IsSecurityExists = FALSE;
|
|
if (!Load::PE::IsDirExists(lpNtHeader, IMAGE_DIRECTORY_ENTRY_SECURITY, &IsSecurityExists))
|
|
{
|
|
Utils::Printf::Fail("Cannot check if IMAGE_DIRECTORY_ENTRY_SECURITY table exists");
|
|
return FALSE;
|
|
};
|
|
if (IsSecurityExists)
|
|
{
|
|
DWORD dwSecurityBaseOffset = 0;
|
|
DWORD dwSecuritySize = 0;
|
|
if (!Load::PE::GetDirectoryInfo(
|
|
lpNtHeader,
|
|
IMAGE_DIRECTORY_ENTRY_SECURITY,
|
|
&dwSecurityBaseOffset,
|
|
&dwSecuritySize,
|
|
FALSE
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Unable to get the IMAGE_DIRECTORY_ENTRY_SECURITY table information");
|
|
return FALSE;
|
|
};
|
|
if (dwSecurityBaseOffset >= dwShellcodeOffset)
|
|
{
|
|
GET_DIRECTORY_ENTRY(lpNtHeader, IMAGE_DIRECTORY_ENTRY_SECURITY) += dwPaddedShellcodeSize;
|
|
};
|
|
};
|
|
}
|
|
else dwShellcodeRVA =
|
|
dwShellcodeOffset - lpExecutableSection->PointerToRawData + lpExecutableSection->VirtualAddress;
|
|
|
|
for (auto const& ObfuscateByNameElement : ObfuscateByNameArr)
|
|
{
|
|
CopyMemory(
|
|
(LPVOID)((DWORD_PTR)lpShellCode + dwShellcodeSize),
|
|
ObfuscateByNameElement.szOldApi,
|
|
strlen(ObfuscateByNameElement.szOldApi) + 1
|
|
);
|
|
dwShellcodeSize += (DWORD)strlen(ObfuscateByNameElement.szOldApi) + 1;
|
|
|
|
CopyMemory(
|
|
(LPVOID)((uintptr_t)lpShellCode + dwShellcodeSize),
|
|
(LPVOID)&ObfuscateByNameElement.dwFThunkRva,
|
|
sizeof(ObfuscateByNameElement.dwFThunkRva)
|
|
);
|
|
dwShellcodeSize += (DWORD)sizeof(ObfuscateByNameElement.dwFThunkRva);
|
|
|
|
DWORD lpApiImportOffset = (DWORD)ObfuscateByNameElement.lpOThunk->u1.AddressOfData;
|
|
if (!Utils::RvaToOffset(lpNtHeader, lpApiImportOffset, &lpApiImportOffset))
|
|
{
|
|
Utils::Printf::Fail("Unable to get the IMAGE_IMPORT_BY_NAME structure pointer");
|
|
return FALSE;
|
|
};
|
|
|
|
if (lpApiImportOffset >=
|
|
(lpExecutableSection->PointerToRawData + lpExecutableSection->SizeOfRawData - dwRawSizeNeeded))
|
|
{
|
|
lpApiImportOffset -= dwRawSizeNeeded;
|
|
};
|
|
|
|
PIMAGE_IMPORT_BY_NAME lpApiImport = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)lpPeFileInfo->lpDataBuffer + lpApiImportOffset);
|
|
LPVOID lpOldApi = (PCHAR)lpApiImport->Name;
|
|
|
|
if (!Utils::IsValidReadPtr(
|
|
lpApiImport,
|
|
sizeof(IMAGE_IMPORT_BY_NAME)
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Invalid import directory");
|
|
return FALSE;
|
|
};
|
|
|
|
ZeroMemory(
|
|
lpApiImport->Name,
|
|
(SIZE_T)strlen((PCHAR)lpApiImport->Name) + 1
|
|
);
|
|
|
|
if (strlen(ObfuscateByNameElement.szNewApi) > strlen(ObfuscateByNameElement.szOldApi))
|
|
{
|
|
CopyMemory(
|
|
(LPVOID)((uintptr_t)lpShellCode + dwNewApisArrayOffset),
|
|
&lpApiImport->Hint,
|
|
sizeof(lpApiImport->Hint)
|
|
);
|
|
ObfuscateByNameElement.lpOThunk->u1.AddressOfData = (uintptr_t)dwShellcodeRVA + (uintptr_t)dwNewApisArrayOffset;
|
|
dwNewApisArrayOffset += (DWORD)sizeof(lpApiImport->Hint);
|
|
|
|
CopyMemory(
|
|
(LPVOID)((uintptr_t)lpShellCode + dwNewApisArrayOffset),
|
|
ObfuscateByNameElement.szNewApi,
|
|
strlen(ObfuscateByNameElement.szNewApi) + 1
|
|
);
|
|
dwNewApisArrayOffset += (DWORD)strlen(ObfuscateByNameElement.szNewApi) + 1;
|
|
}
|
|
else
|
|
{
|
|
if (!Utils::SafeMemoryCopy(
|
|
lpOldApi,
|
|
(DWORD)strlen(ObfuscateByNameElement.szOldApi),
|
|
(LPVOID)ObfuscateByNameElement.szNewApi,
|
|
(DWORD)strlen(ObfuscateByNameElement.szNewApi)
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Unable to change the api name from %s to %s", ObfuscateByNameElement.szOldApi, ObfuscateByNameElement.szNewApi);
|
|
return FALSE;
|
|
};
|
|
};
|
|
Utils::Printf::Success("Patched %s to be %s", ObfuscateByNameElement.szOldApi, ObfuscateByNameElement.szNewApi);
|
|
};
|
|
dwShellcodeSize = dwNewApisArrayOffset;
|
|
|
|
DWORD dwJmpDiff = dwShellcodeRVA - lpNtHeader->OptionalHeader.AddressOfEntryPoint - sizeof(bOriginalBytes);
|
|
PBYTE bJmpDiffBytes = (PBYTE)& dwJmpDiff;
|
|
|
|
BYTE bNewBytes[] =
|
|
{
|
|
0xE8,
|
|
bJmpDiffBytes[0], bJmpDiffBytes[1],
|
|
bJmpDiffBytes[2], bJmpDiffBytes[3]
|
|
};
|
|
if (!Utils::SafeMemoryCopy(
|
|
lpEntry,
|
|
sizeof(bOriginalBytes),
|
|
(LPVOID)bNewBytes,
|
|
sizeof(bOriginalBytes)
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Unable to write the new 5 bytes to the entry point");
|
|
return FALSE;
|
|
};
|
|
|
|
LPVOID lpWholeShellCode = NULL;
|
|
if (!(lpWholeShellCode = VirtualAlloc(
|
|
NULL,
|
|
dwPaddedShellcodeSize,
|
|
MEM_COMMIT | MEM_RESERVE,
|
|
PAGE_READWRITE
|
|
)))
|
|
{
|
|
Utils::Reportf::ApiError("VirtualAlloc", "Cannot allocate the size of %d, for the shellcode", dwPaddedShellcodeSize);
|
|
return FALSE;
|
|
};
|
|
|
|
if (!Utils::SafeMemoryCopy(
|
|
lpWholeShellCode,
|
|
dwPaddedShellcodeSize,
|
|
lpShellCode,
|
|
dwShellcodeSize
|
|
))
|
|
{
|
|
Utils::Printf::Fail("Cannot write the shellcode");
|
|
return FALSE;
|
|
};
|
|
|
|
if (!DeleteFileA(szOutFileName))
|
|
{
|
|
if (ERROR_FILE_NOT_FOUND != GetLastError()) {
|
|
Utils::Reportf::ApiError("DeleteFileA", "Out file %s cannot be deleted", szOutFileName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
HANDLE hFile = NULL;
|
|
if (!(hFile = CreateFileA(
|
|
szOutFileName,
|
|
FILE_APPEND_DATA | GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
)) || INVALID_HANDLE_VALUE == hFile)
|
|
{
|
|
Utils::Reportf::ApiError("CreateFileA", "Cannot create the out file %s", szOutFileName);
|
|
return FALSE;
|
|
};
|
|
|
|
DWORD dwWrittenBytes = 0;
|
|
if (!WriteFile(
|
|
hFile,
|
|
lpPeFileInfo->lpDataBuffer,
|
|
dwShellcodeOffset,
|
|
&dwWrittenBytes,
|
|
NULL
|
|
) || dwWrittenBytes != dwShellcodeOffset)
|
|
{
|
|
Utils::Reportf::ApiError("WriteFile", "Cannot write to the out file %s", szOutFileName);
|
|
return FALSE;
|
|
};
|
|
|
|
if (!WriteFile(
|
|
hFile,
|
|
lpWholeShellCode,
|
|
dwPaddedShellcodeSize,
|
|
&dwWrittenBytes,
|
|
NULL
|
|
) || dwWrittenBytes != dwPaddedShellcodeSize)
|
|
{
|
|
Utils::Reportf::ApiError("WriteFile", "Cannot write to the out file %s", szOutFileName);
|
|
return FALSE;
|
|
};
|
|
|
|
dwShellcodeOffset = Utils::AlignUp(
|
|
dwShellcodeOffset,
|
|
lpNtHeader->OptionalHeader.FileAlignment
|
|
);
|
|
|
|
if (!WriteFile(
|
|
hFile,
|
|
(LPCVOID)((DWORD_PTR)lpPeFileInfo->lpDataBuffer + dwShellcodeOffset),
|
|
lpPeFileInfo->dwSize - dwShellcodeOffset,
|
|
&dwWrittenBytes,
|
|
NULL
|
|
) || dwWrittenBytes != lpPeFileInfo->dwSize - dwShellcodeOffset)
|
|
{
|
|
Utils::Reportf::ApiError("WriteFile", "Cannot write to the out file %s", szOutFileName);
|
|
return FALSE;
|
|
};
|
|
|
|
LARGE_INTEGER ZeroPointer;
|
|
ZeroMemory
|
|
(
|
|
&ZeroPointer,
|
|
sizeof(LARGE_INTEGER)
|
|
);
|
|
|
|
if (!SetFilePointerEx
|
|
(
|
|
hFile,
|
|
ZeroPointer,
|
|
NULL,
|
|
FILE_BEGIN
|
|
))
|
|
{
|
|
Utils::Reportf::ApiError("SetFilePointerEx", "Error setting pointer at the begin of the saved file");
|
|
return FALSE;
|
|
};
|
|
|
|
LARGE_INTEGER u32FileSize;
|
|
if (!GetFileSizeEx(
|
|
hFile,
|
|
&u32FileSize
|
|
))
|
|
{
|
|
Utils::Reportf::ApiError("GetFileSizeEx", "Error while getting the size of the saved file");
|
|
return FALSE;
|
|
};
|
|
|
|
DWORD dwAlignedSize = Utils::AlignUp(
|
|
(DWORD)u32FileSize.QuadPart,
|
|
sizeof(DWORD)
|
|
);
|
|
|
|
LPVOID bFileContent = NULL;
|
|
if (!(bFileContent = VirtualAlloc(
|
|
NULL,
|
|
dwAlignedSize,
|
|
(MEM_COMMIT | MEM_RESERVE),
|
|
PAGE_READWRITE
|
|
)))
|
|
{
|
|
Utils::Reportf::ApiError("VirtualAlloc", "Error while allocating for the saved file %d", dwAlignedSize);
|
|
return FALSE;
|
|
};
|
|
|
|
DWORD dwReadBytes = 0;
|
|
if (!ReadFile(
|
|
hFile,
|
|
bFileContent,
|
|
(DWORD)u32FileSize.QuadPart,
|
|
&dwReadBytes,
|
|
NULL
|
|
) || dwReadBytes != u32FileSize.QuadPart)
|
|
{
|
|
Utils::Reportf::ApiError("ReadFile", "Error while reading the saved file %d, %d", dwReadBytes, u32FileSize.QuadPart);
|
|
return FALSE;
|
|
};
|
|
|
|
DWORD dwCheckSumOffset = (DWORD)((uintptr_t)& lpNtHeader->OptionalHeader.CheckSum - (uintptr_t)lpPeFileInfo->lpDataBuffer);
|
|
ULONGLONG CheckSum = 0;
|
|
|
|
for (DWORD dwIndex = 0; dwIndex < u32FileSize.QuadPart / sizeof(DWORD); dwIndex++)
|
|
{
|
|
if (dwIndex == dwCheckSumOffset / sizeof(DWORD))
|
|
{
|
|
continue;
|
|
};
|
|
|
|
CheckSum = (CheckSum & 0xffffffff) + *(PDWORD)((uintptr_t)bFileContent + (ULONGLONG)dwIndex * sizeof(DWORD)) + (CheckSum >> 32);
|
|
if (CheckSum > (2 ^ 32))
|
|
{
|
|
CheckSum = (CheckSum & 0xffffffff) + (CheckSum >> 32);
|
|
};
|
|
};
|
|
|
|
CheckSum = (CheckSum & 0xffff) + (CheckSum >> 16);
|
|
CheckSum = CheckSum + (CheckSum >> 16);
|
|
CheckSum = CheckSum & 0xffff;
|
|
CheckSum += u32FileSize.QuadPart;
|
|
|
|
*(PDWORD)((uintptr_t)bFileContent + dwCheckSumOffset) = (DWORD)CheckSum;
|
|
|
|
if (!Load::File::UnLoad(lpPeFileInfo, sizeof(RAW_FILE_INFO)))
|
|
{
|
|
Utils::Printf::Fail("Cannot unload the PE");
|
|
return FALSE;
|
|
};
|
|
|
|
CloseHandle(hFile);
|
|
hFile = NULL;
|
|
|
|
if (!(hFile = CreateFileA(
|
|
szOutFileName,
|
|
GENERIC_WRITE | GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
TRUNCATE_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
)) || INVALID_HANDLE_VALUE == hFile)
|
|
{
|
|
Utils::Reportf::ApiError("CreateFileA", "Cannot open the saved file");
|
|
return FALSE;
|
|
};
|
|
|
|
if (!WriteFile(
|
|
hFile,
|
|
bFileContent,
|
|
dwAlignedSize,
|
|
&dwWrittenBytes,
|
|
NULL
|
|
) || dwWrittenBytes != dwAlignedSize)
|
|
{
|
|
Utils::Reportf::ApiError("WriteFile", "Cannot write to the saved file");
|
|
return FALSE;
|
|
};
|
|
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
Utils::Printf::Info("%s [in_file] [out_file] [target_api_0],[new_api_0] [target_api_1],[new_api_1] ...\n", argv[0]);
|
|
return TRUE;
|
|
|
|
};
|
|
};
|