mirror of
https://github.com/rbmm/SC
synced 2026-06-08 17:03:41 +00:00
1164 lines
22 KiB
C++
1164 lines
22 KiB
C++
#include "stdafx.h"
|
|
#include "compressapi.h"
|
|
|
|
void PrintUTF8(PCSTR pcsz, ULONG len)
|
|
{
|
|
HANDLE hFile = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
switch ((ULONG_PTR)hFile)
|
|
{
|
|
case 0:
|
|
case (ULONG_PTR)INVALID_HANDLE_VALUE:
|
|
return;
|
|
}
|
|
|
|
WriteFile(hFile, pcsz, len, &len, 0);
|
|
}
|
|
|
|
inline void PrintUTF8(PCSTR pcsz)
|
|
{
|
|
PrintUTF8(pcsz, (ULONG)strlen(pcsz));
|
|
}
|
|
|
|
void PrintUTF8_v(PCSTR format, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
|
|
PSTR buf = 0;
|
|
int len = 0;
|
|
while (0 < (len = _vsnprintf(buf, len, format, ap)))
|
|
{
|
|
if (buf)
|
|
{
|
|
PrintUTF8(buf, len);
|
|
break;
|
|
}
|
|
|
|
buf = (PSTR)alloca(++len);
|
|
}
|
|
}
|
|
|
|
#define DbgPrint PrintUTF8_v
|
|
|
|
HRESULT PrintError(HRESULT dwError)
|
|
{
|
|
LPCVOID lpSource = 0;
|
|
ULONG dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS;
|
|
|
|
if ((dwError & FACILITY_NT_BIT) || (0 > dwError && HRESULT_FACILITY(dwError) == FACILITY_NULL))
|
|
{
|
|
dwError &= ~FACILITY_NT_BIT;
|
|
__nt:
|
|
dwFlags = FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS;
|
|
|
|
lpSource = GetModuleHandle(L"ntdll");
|
|
}
|
|
|
|
PSTR lpText;
|
|
if (ULONG cch = FormatMessageA(dwFlags, lpSource, dwError, 0, (PSTR)&lpText, 0, 0))
|
|
{
|
|
PrintUTF8(lpText, cch);
|
|
LocalFree(lpText);
|
|
}
|
|
else if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
|
|
{
|
|
goto __nt;
|
|
}
|
|
|
|
DbgPrint("0x%x (%d)\r\n", dwError, dwError);
|
|
return dwError;
|
|
}
|
|
|
|
NTSTATUS ReadFromFile(_In_ PCWSTR lpFileName,
|
|
_Out_ PBYTE* ppb,
|
|
_Out_ ULONG* pcb,
|
|
_In_opt_ ULONG cbBefore = 0,
|
|
_In_opt_ ULONG cbAfter = 0)
|
|
{
|
|
UNICODE_STRING ObjectName;
|
|
NTSTATUS status = RtlDosPathNameToNtPathName_U_WithStatus(lpFileName, &ObjectName, 0, 0);
|
|
|
|
DbgPrint("DosPathNameToNt(\"%ws\") = %x\r\n", lpFileName, status);
|
|
|
|
if (0 <= status)
|
|
{
|
|
HANDLE hFile;
|
|
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
|
|
IO_STATUS_BLOCK iosb;
|
|
status = NtOpenFile(&hFile, FILE_GENERIC_READ, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
DbgPrint("NtOpenFile(\"%wZ\") = %x\r\n", &ObjectName, status);
|
|
|
|
RtlFreeUnicodeString(&ObjectName);
|
|
|
|
if (0 <= status)
|
|
{
|
|
FILE_STANDARD_INFORMATION fsi;
|
|
if (0 <= (status = NtQueryInformationFile(hFile, &iosb, &fsi, sizeof(fsi), FileStandardInformation)))
|
|
{
|
|
DbgPrint("FileSize=%I64u\r\n", fsi.EndOfFile.QuadPart);
|
|
|
|
if (fsi.EndOfFile.QuadPart < 0x1000000)
|
|
{
|
|
if (PBYTE pb = new BYTE[cbBefore + fsi.EndOfFile.LowPart + cbAfter])
|
|
{
|
|
if (0 > (status = NtReadFile(hFile, 0, 0, 0, &iosb, pb + cbBefore, fsi.EndOfFile.LowPart, 0, 0)))
|
|
{
|
|
delete[] pb;
|
|
}
|
|
else
|
|
{
|
|
*ppb = pb;
|
|
*pcb = (ULONG)iosb.Information;
|
|
}
|
|
|
|
DbgPrint("NtReadFile=%x\r\n", status);
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_FILE_TOO_LARGE;
|
|
}
|
|
}
|
|
|
|
NtClose(hFile);
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS SaveToFile(_In_ PCWSTR lpFileName, _In_ const void* lpBuffer, _In_ ULONG nNumberOfBytesToWrite)
|
|
{
|
|
UNICODE_STRING ObjectName;
|
|
NTSTATUS status = RtlDosPathNameToNtPathName_U_WithStatus(lpFileName, &ObjectName, 0, 0);
|
|
|
|
DbgPrint("DosPathNameToNt(\"%ws\") = %x\r\n", lpFileName, status);
|
|
|
|
if (0 <= status)
|
|
{
|
|
HANDLE hFile;
|
|
IO_STATUS_BLOCK iosb;
|
|
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
|
|
|
|
LARGE_INTEGER AllocationSize = { nNumberOfBytesToWrite };
|
|
|
|
status = NtCreateFile(&hFile, FILE_APPEND_DATA | SYNCHRONIZE, &oa, &iosb, &AllocationSize,
|
|
0, 0, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, 0, 0);
|
|
|
|
DbgPrint("CreateFile(\"%wZ\") = %x\r\n", &ObjectName, status);
|
|
|
|
RtlFreeUnicodeString(&ObjectName);
|
|
|
|
if (0 <= status)
|
|
{
|
|
status = NtWriteFile(hFile, 0, 0, 0, &iosb, const_cast<void*>(lpBuffer), nNumberOfBytesToWrite, 0, 0);
|
|
NtClose(hFile);
|
|
DbgPrint("WriteFile(%x) = %x\r\n", nNumberOfBytesToWrite, status);
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
struct IMP_HELP
|
|
{
|
|
PVOID _M_hmod;
|
|
PIMAGE_IMPORT_DESCRIPTOR _M_piid;
|
|
|
|
void** _M_pFunction = 0;
|
|
PIMAGE_THUNK_DATA _M_pThunk = 0;
|
|
|
|
ULONG _M_n;
|
|
|
|
char _M_buf[32];
|
|
|
|
PCSTR GetName(ULONG rva);
|
|
|
|
BOOL Init(PVOID hmod);
|
|
|
|
NTSTATUS ProcessMAP(
|
|
PCWSTR pszImp,
|
|
PSTR pcsz,
|
|
ULONG iSection,
|
|
ULONG ofs,
|
|
ULONG_PTR Va,
|
|
ULONG s);
|
|
|
|
NTSTATUS ProcessMAP(
|
|
PCWSTR pszImp,
|
|
PCWSTR pszMap,
|
|
ULONG iSection,
|
|
ULONG ofs,
|
|
ULONG_PTR Va,
|
|
ULONG s);
|
|
|
|
PCSTR GetName(ULONG rva, DWORD FirstThunk, void** pFunction, PIMAGE_THUNK_DATA pThunk);
|
|
};
|
|
|
|
BOOL IMP_HELP::Init(PVOID hmod)
|
|
{
|
|
ULONG s;
|
|
if (PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(
|
|
hmod, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &s))
|
|
{
|
|
if (s /= sizeof(IMAGE_IMPORT_DESCRIPTOR))
|
|
{
|
|
_M_n = s, _M_piid = piid, _M_hmod = hmod;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
PCSTR IMP_HELP::GetName(ULONG rva, DWORD FirstThunk, void** pFunction, PIMAGE_THUNK_DATA pThunk)
|
|
{
|
|
while (void* Function = *pFunction++)
|
|
{
|
|
IMAGE_THUNK_DATA Thunk = *pThunk++;
|
|
|
|
if (rva == FirstThunk)
|
|
{
|
|
_M_pFunction = pFunction;
|
|
_M_pThunk = pThunk;
|
|
|
|
if (IMAGE_SNAP_BY_ORDINAL(Thunk.u1.Ordinal))
|
|
{
|
|
if (0 < sprintf_s(_M_buf, _countof(_M_buf), "#%u", (ULONG)IMAGE_ORDINAL(Thunk.u1.Ordinal)))
|
|
{
|
|
return _M_buf;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
return (PCSTR)reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
|
|
RtlOffsetToPointer(_M_hmod, Thunk.u1.AddressOfData))->Name;
|
|
}
|
|
|
|
FirstThunk += sizeof(PVOID);
|
|
}
|
|
|
|
_M_pFunction = 0;
|
|
_M_pThunk = 0;
|
|
return 0;
|
|
}
|
|
|
|
PCSTR GetNameFormat(PCSTR str, PCSTR name, ULONG* pn)
|
|
{
|
|
*pn = 0;
|
|
if (strcmp(name, str))
|
|
{
|
|
#ifdef _X86_
|
|
BOOL f = FALSE;
|
|
switch (*name++)
|
|
{
|
|
case '@':
|
|
f = TRUE;
|
|
case '_':
|
|
if (PCSTR pc = strchr(name, '@'))
|
|
{
|
|
if (!memcmp(name, str, pc - name))
|
|
{
|
|
ULONG n = strtoul(pc + 1, const_cast<PSTR*>(&pc), 10);
|
|
if (!*pc && !(n & 3))
|
|
{
|
|
*pn = n;
|
|
// __fastcall : __stdcall
|
|
return f ? "createFuncF %hs, %hs, %u\r\n" : "createFuncS %hs, %hs, %u\r\n";
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(name, str))
|
|
{
|
|
// __cdecl
|
|
return "createFuncC %hs, %hs\r\n";
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
// name == str
|
|
return "createFunc %hs, %hs\r\n";
|
|
}
|
|
|
|
PCSTR IMP_HELP::GetName(ULONG rva)
|
|
{
|
|
PVOID hmod = _M_hmod;
|
|
ULONG n = _M_n;
|
|
PIMAGE_IMPORT_DESCRIPTOR piid = _M_piid;
|
|
|
|
if (void** pFunction = _M_pFunction)
|
|
{
|
|
if (PCSTR name = GetName(rva, RtlPointerToOffset(hmod, pFunction), pFunction, _M_pThunk))
|
|
{
|
|
return name;
|
|
}
|
|
}
|
|
|
|
do
|
|
{
|
|
DWORD Name = piid->Name;
|
|
|
|
if (!Name)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (DWORD FirstThunk = piid->FirstThunk)
|
|
{
|
|
if (rva < FirstThunk)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (DWORD OriginalFirstThunk = piid->OriginalFirstThunk)
|
|
{
|
|
if (PCSTR name = GetName(rva, FirstThunk,
|
|
(void**)RtlOffsetToPointer(hmod, FirstThunk),
|
|
(PIMAGE_THUNK_DATA)RtlOffsetToPointer(hmod, OriginalFirstThunk)))
|
|
{
|
|
return name;
|
|
}
|
|
}
|
|
}
|
|
|
|
} while (piid++, --n);
|
|
|
|
return 0;
|
|
}
|
|
|
|
NTSTATUS IMP_HELP::ProcessMAP(
|
|
PCWSTR pszImp,
|
|
PSTR pcsz,
|
|
ULONG iSection,
|
|
ULONG ofs,
|
|
ULONG_PTR Va,
|
|
ULONG s)
|
|
{
|
|
PSTR buf = pcsz, psz = buf;
|
|
|
|
ULONG64 u;
|
|
BOOL f = FALSE;
|
|
ULONG_PTR ImageBase = 0;
|
|
__0:
|
|
|
|
PSTR pcszLine = pcsz;
|
|
|
|
static const char plai[] = " Preferred load address is ";
|
|
|
|
//while (!IsDebuggerPresent()) Sleep(1000); __debugbreak();
|
|
|
|
if (!f && !memcmp(pcsz, plai, _countof(plai) - 1))
|
|
{
|
|
if (ImageBase)
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
u = _strtoui64(pcsz + _countof(plai) - 1, const_cast<char**>(&pcsz), 16);
|
|
|
|
if (!u || '\r' != *pcsz++ || '\n' != *pcsz++)
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
ImageBase = (ULONG_PTR)u;
|
|
Va += ImageBase;
|
|
|
|
DbgPrint("ImageBase = %p, Va = %p\r\n", ImageBase, Va);
|
|
|
|
goto __0;
|
|
}
|
|
|
|
ULONG i = strtoul(pcsz, const_cast<char**>(&pcsz), 16);
|
|
|
|
if (':' != *pcsz)
|
|
{
|
|
__1:
|
|
if (!(pcsz = strchr(pcsz, '\r')) || '\n' != *++pcsz)
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
++pcsz;
|
|
goto __0;
|
|
}
|
|
|
|
if (i != iSection)
|
|
{
|
|
goto __1;
|
|
}
|
|
|
|
i = strtoul(pcsz + 1, const_cast<char**>(&pcsz), 16);
|
|
|
|
if (' ' != *pcsz)
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
if (i != ofs)
|
|
{
|
|
goto __1;
|
|
}
|
|
|
|
if (f)
|
|
{
|
|
pcsz = pcszLine;
|
|
}
|
|
else
|
|
{
|
|
i = strtoul(pcsz + 1, &pcsz, 16);
|
|
|
|
if ('H' != *pcsz || s != i)
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
f = TRUE;
|
|
goto __1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS status;
|
|
|
|
__loop:
|
|
|
|
i = strtoul(pcsz, const_cast<char**>(&pcsz), 16);
|
|
|
|
if (':' != *pcsz || iSection != i)
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
i = strtoul(pcsz + 1, const_cast<char**>(&pcsz), 16);
|
|
|
|
if (' ' != *pcsz || ofs != i)
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
ofs += sizeof(PVOID);
|
|
BOOL __imp_ = FALSE;
|
|
|
|
__space:
|
|
switch (*pcsz++)
|
|
{
|
|
case ' ':
|
|
goto __space;
|
|
|
|
default:
|
|
return STATUS_BAD_DATA;
|
|
|
|
case '_':
|
|
if (memcmp(pcsz, "_imp_", 5))
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
pcsz += 5;
|
|
__imp_ = TRUE;
|
|
|
|
case '\\':
|
|
INT k = -1;
|
|
|
|
PCSTR name = pcsz;
|
|
|
|
while (' ' < *pcsz) pcsz++;
|
|
|
|
*pcsz++ = 0;
|
|
|
|
if (!strcmp(name, "__chkstk") || !strcmp(name, "__alloca_probe"))
|
|
{
|
|
DbgPrint("!!!! %hs\\%hs imported !!!!!\r\n", "__chkstk", "__alloca_probe");
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
u = _strtoui64(pcsz, const_cast<char**>(&pcsz), 16);
|
|
|
|
if (Va != u)
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
Va += sizeof(PVOID);
|
|
|
|
PCSTR pszLib = 0;
|
|
|
|
__00:
|
|
switch (*pcsz)
|
|
{
|
|
case 0:
|
|
return STATUS_BAD_DATA;
|
|
case ':':
|
|
*pcsz++ = 0;
|
|
goto __01;
|
|
default:
|
|
if (!pszLib)
|
|
{
|
|
pszLib = pcsz;
|
|
}
|
|
case ' ':
|
|
pcsz++;
|
|
goto __00;
|
|
}
|
|
__01:
|
|
|
|
PCSTR pszDLL = pcsz;
|
|
|
|
__02:
|
|
switch (*pcsz++)
|
|
{
|
|
case 0:
|
|
case ':':
|
|
return STATUS_BAD_DATA;
|
|
default:
|
|
goto __02;
|
|
case '\r':
|
|
pcsz[-1] = 0;
|
|
break;
|
|
}
|
|
|
|
if ('\n' != *pcsz++)
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
|
|
ULONG cb = RtlPointerToOffset(psz, name);
|
|
|
|
if (__imp_)
|
|
{
|
|
__imp_ = FALSE;
|
|
|
|
if (PCSTR str = GetName((ULONG)(u - ImageBase)))
|
|
{
|
|
ULONG np;
|
|
if (PCSTR fmt = GetNameFormat(str, name, &np))
|
|
{
|
|
k = sprintf_s(psz, cb, fmt, pszLib, str, np);
|
|
}
|
|
else
|
|
{
|
|
k = sprintf_s(psz, cb, "createFunc? %hs, %hs, '%hs'\r\n", pszLib, name, str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!_stricmp(pszDLL, "ntdll.dll"))
|
|
{
|
|
pszDLL = "";
|
|
}
|
|
|
|
k = sprintf_s(psz, cb, "\r\nHMOD %hs, <%hs>\r\n\r\n", pszLib, pszDLL);
|
|
}
|
|
|
|
if (0 >= k)
|
|
{
|
|
return STATUS_INTERNAL_ERROR;
|
|
}
|
|
|
|
psz += k;
|
|
|
|
if (s -= sizeof(PVOID))
|
|
{
|
|
goto __loop;
|
|
}
|
|
|
|
status = SaveToFile(pszImp, buf, RtlPointerToOffset(buf, psz));
|
|
return 0 > status ? status : STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
}
|
|
|
|
NTSTATUS IMP_HELP::ProcessMAP(
|
|
PCWSTR pszImp,
|
|
PCWSTR pszMap,
|
|
ULONG iSection,
|
|
ULONG ofs,
|
|
ULONG_PTR Va,
|
|
ULONG s)
|
|
{
|
|
PBYTE pb;
|
|
ULONG cb;
|
|
|
|
DbgPrint("ProcessMAP(%04x:%08x %p [%x])...\r\n", iSection, ofs, Va, s);
|
|
|
|
NTSTATUS status = ReadFromFile(pszMap, &pb, &cb, 0, 1);
|
|
|
|
if (0 <= status)
|
|
{
|
|
pb[cb - 1] = 0;
|
|
status = ProcessMAP(pszImp, (PSTR)pb, iSection, ofs, Va, s);
|
|
delete[] pb;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS ProcessIAT(PCWSTR pszImp, PCWSTR pszMap, ULONG_PTR pvShellEnd)
|
|
{
|
|
if (PVOID hmod = GetModuleHandleW(0))
|
|
{
|
|
ULONG s;
|
|
|
|
union {
|
|
PVOID pv;
|
|
PBYTE pb;
|
|
PIMAGE_BASE_RELOCATION pibr;
|
|
};
|
|
|
|
if (pv = RtlImageDirectoryEntryToData(hmod, TRUE, IMAGE_DIRECTORY_ENTRY_IAT, &s))
|
|
{
|
|
DbgPrint("IAT: %p [%x]\r\n", pv, s);
|
|
|
|
if (!s || (s & (sizeof(PVOID) - 1)))
|
|
{
|
|
return STATUS_INTERNAL_ERROR;
|
|
}
|
|
|
|
if (PIMAGE_NT_HEADERS pinth = RtlImageNtHeader(hmod))
|
|
{
|
|
if (ULONG NumberOfSections = pinth->FileHeader.NumberOfSections)
|
|
{
|
|
ULONG_PTR Rva = (ULONG_PTR)pv - (ULONG_PTR)hmod;
|
|
|
|
ULONG iSection = 0;
|
|
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinth);
|
|
do
|
|
{
|
|
++iSection;
|
|
|
|
ULONG_PTR Ofs = Rva - pish->VirtualAddress;
|
|
|
|
if (Ofs < pish->Misc.VirtualSize)
|
|
{
|
|
if (Ofs + s <= pish->Misc.VirtualSize)
|
|
{
|
|
IMP_HELP imh;
|
|
if (imh.Init(hmod))
|
|
{
|
|
return imh.ProcessMAP(pszImp, pszMap, iSection, (ULONG)Ofs, Rva, s);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
} while (pish++, --NumberOfSections);
|
|
}
|
|
}
|
|
|
|
return STATUS_INTERNAL_ERROR;
|
|
}
|
|
|
|
if (pv = RtlImageDirectoryEntryToData(hmod, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &s))
|
|
{
|
|
pvShellEnd -= (ULONG_PTR)hmod;
|
|
|
|
#ifdef _X86_
|
|
BOOL bFirst = TRUE;
|
|
PVOID pvTarget = 0;
|
|
#endif // _X86_
|
|
|
|
do
|
|
{
|
|
ULONG SizeOfBlock = pibr->SizeOfBlock;
|
|
|
|
if (SizeOfBlock < sizeof(IMAGE_BASE_RELOCATION))
|
|
{
|
|
return STATUS_INVALID_IMAGE_FORMAT;
|
|
}
|
|
|
|
ULONG VirtualAddress = pibr->VirtualAddress;
|
|
|
|
struct TYPE_OFFSET
|
|
{
|
|
WORD ofs : 12;
|
|
WORD type : 4;
|
|
}*pu = (TYPE_OFFSET*)(pibr + 1);
|
|
|
|
pb += SizeOfBlock, s -= SizeOfBlock, SizeOfBlock -= sizeof(IMAGE_BASE_RELOCATION);
|
|
|
|
if (SizeOfBlock & (sizeof(WORD) - 1))
|
|
{
|
|
return STATUS_INVALID_IMAGE_FORMAT;
|
|
}
|
|
|
|
SizeOfBlock >>= 1;
|
|
|
|
do
|
|
{
|
|
if (pu->type)
|
|
{
|
|
//DbgPrint("\t## %x %08x\r\n", pu->type, VirtualAddress + pu->ofs);
|
|
|
|
if (VirtualAddress + pu->ofs < pvShellEnd)
|
|
{
|
|
ULONG rva = VirtualAddress + pu->ofs;
|
|
union {
|
|
PVOID prv;
|
|
PBYTE prb;
|
|
PULONG pru;
|
|
};
|
|
prv = RtlOffsetToPointer(hmod, rva);
|
|
|
|
#ifdef _X86_
|
|
|
|
if (IMAGE_REL_BASED_HIGHLOW == pu->type)
|
|
{
|
|
ULONG Target = *pru - (ULONG)hmod;
|
|
DbgPrint("!! Exist Relocs: %08x -> %08x\r\n", rva, Target);
|
|
|
|
// while (!IsDebuggerPresent()) Sleep(1000); __debugbreak();
|
|
if (pvShellEnd <= Target)
|
|
{
|
|
DbgPrint("reloc to %08x beyond shell end (%08x)\r\n", Target, pvShellEnd);
|
|
return STATUS_ILLEGAL_DLL_RELOCATION;
|
|
}
|
|
|
|
if (bFirst)
|
|
{
|
|
bFirst = FALSE;
|
|
if (Target + 8 != rva)
|
|
{
|
|
DbgPrint("_Target(%p) + 8 != rva(%x)\r\n", Target, rva);
|
|
return STATUS_ILLEGAL_DLL_RELOCATION;
|
|
}
|
|
|
|
pvTarget = RtlOffsetToPointer(hmod, Target);
|
|
|
|
DbgPrint("__Address: %p\r\n", pvTarget);
|
|
}
|
|
else
|
|
{
|
|
CHAR msg[0x80];
|
|
ULONG cch = _countof(msg);
|
|
if (CryptBinaryToStringA((PBYTE)*pru, 16, CRYPT_STRING_HEXASCII, msg, &cch))
|
|
{
|
|
DbgPrint("\t%hs\r\n", msg);
|
|
}
|
|
#if 0
|
|
// mov ecx,offset x
|
|
if (0xb9 != prb[-1])
|
|
{
|
|
return STATUS_ILLEGAL_DLL_RELOCATION;
|
|
}
|
|
++pru;
|
|
|
|
// call __Address;
|
|
if (0xe8 != *prb++)
|
|
{
|
|
return STATUS_ILLEGAL_DLL_RELOCATION;
|
|
}
|
|
|
|
ULONG ofs = *pru++;
|
|
|
|
DbgPrint("call %p (%p + %08x)\r\n", prb + ofs, prb, ofs);
|
|
|
|
if (prb + ofs != pvTarget)
|
|
{
|
|
return STATUS_ILLEGAL_DLL_RELOCATION;
|
|
}
|
|
#endif // 0
|
|
}
|
|
}
|
|
else
|
|
#endif // _X86_
|
|
{
|
|
DbgPrint("######## !! Exist Relocs (%x:%08x) !! ########\r\n", pu->type, rva);
|
|
return STATUS_ILLEGAL_DLL_RELOCATION;
|
|
}
|
|
}
|
|
}
|
|
} while (pu++, --SizeOfBlock);
|
|
|
|
} while (s);
|
|
}
|
|
|
|
DbgPrint("!! NO IMPORT, NO RELOCS. OK !!\r\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return STATUS_INTERNAL_ERROR;
|
|
}
|
|
|
|
NTSTATUS I_CreateAsmSC(PCWSTR pwzFileName, const void* pcv, SIZE_T cb)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
union {
|
|
const void* pv;
|
|
PULONG64 pu64;
|
|
PULONG pu;
|
|
PUSHORT ps;
|
|
PUCHAR pb;
|
|
};
|
|
|
|
pv = pcv;
|
|
|
|
SIZE_T n = cb >> 3;
|
|
SIZE_T cch = n * (7 + 16) + 36;
|
|
// DD 0ABCDEF78h.. ; 7+8
|
|
// DW 0ABCDh.. ; 7+4
|
|
// DB 0ABh.. ; 7+2
|
|
|
|
if (PSTR buf = new char [cch])
|
|
{
|
|
status = STATUS_INTERNAL_ERROR;
|
|
|
|
int len;
|
|
ULONG s = 4;
|
|
|
|
PSTR psz = buf;
|
|
|
|
if (n)
|
|
{
|
|
cb -= n << 3;
|
|
|
|
do
|
|
{
|
|
if (0 >= (len = sprintf_s(psz, cch, "DQ 0%016I64xh\r\n", *pu64++)))
|
|
{
|
|
goto __exit;
|
|
}
|
|
|
|
} while (psz += len, cch -= len, --n);
|
|
}
|
|
|
|
static const PCSTR fmt[] = { "DB 0%02xh\r\n", "DW 0%04xh\r\n", "DD 0%08xh\r\n" };
|
|
n = _countof(fmt) - 1;
|
|
|
|
do
|
|
{
|
|
if (s <= cb)
|
|
{
|
|
cb -= s;
|
|
|
|
if (0 >= (len = sprintf_s(psz, cch, fmt[n], *pu & ((1ULL << (s << 3)) - 1))))
|
|
{
|
|
goto __exit;
|
|
}
|
|
|
|
psz += len, cch -= len, pb += s;
|
|
}
|
|
|
|
} while (s >>= 1, n--);
|
|
|
|
status = SaveToFile(pwzFileName, buf, RtlPointerToOffset(buf, psz));
|
|
|
|
__exit:
|
|
delete[] buf;
|
|
|
|
DbgPrint("CreateAsmSC(%ws)=%x\r\n", pwzFileName, status);
|
|
|
|
return status;
|
|
}
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
inline ULONG BOOL_TO_ERROR(BOOL f)
|
|
{
|
|
return f ? NOERROR : GetLastError();
|
|
}
|
|
|
|
//## -> #
|
|
//#. -> *
|
|
//#: -> %
|
|
|
|
BOOL UnEscape(_Inout_ PWSTR str)
|
|
{
|
|
PWSTR buf = str;
|
|
WCHAR c;
|
|
do
|
|
{
|
|
if ('#' == (c = *str++))
|
|
{
|
|
switch (c = *str++)
|
|
{
|
|
case '.':
|
|
c = '*';
|
|
break;
|
|
case ':':
|
|
c = '%';
|
|
break;
|
|
case '#':
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
*buf++ = c;
|
|
|
|
} while (c);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
NTSTATUS CreateAesKey(_Out_ BCRYPT_KEY_HANDLE* phKey, _In_ PBYTE secret, _In_ ULONG cb)
|
|
{
|
|
NTSTATUS status;
|
|
BCRYPT_ALG_HANDLE hAlgorithm;
|
|
if (0 <= (status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_AES_ALGORITHM, 0, 0)))
|
|
{
|
|
status = BCryptGenerateSymmetricKey(hAlgorithm, phKey, 0, 0, secret, cb, 0);
|
|
|
|
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS CreateAsmSC(PCWSTR to, PVOID pv, ULONG cb)
|
|
{
|
|
if (PWSTR psz = wcsrchr(to, '?'))
|
|
{
|
|
*psz++ = 0;
|
|
|
|
//while (!IsDebuggerPresent()) Sleep(100); __debugbreak();
|
|
if (!UnEscape(const_cast<PWSTR>(to)))
|
|
{
|
|
return STATUS_BAD_DATA;
|
|
}
|
|
DbgPrint("password: \"%ws\"\r\n", to);
|
|
|
|
BCRYPT_KEY_HANDLE hKey;
|
|
UCHAR secret[32];
|
|
ULONG s = sizeof(secret);
|
|
if (CryptHashCertificate2(BCRYPT_SHA256_ALGORITHM, 0, 0, (PBYTE)to, RtlPointerToOffset(to, psz), secret, &s))
|
|
{
|
|
NTSTATUS status = CreateAesKey(&hKey, secret, s);
|
|
|
|
if (0 <= status)
|
|
{
|
|
PBYTE pb = 0;
|
|
s = 0;
|
|
while (0 <= (status = BCryptEncrypt(hKey, (PBYTE)pv, cb, 0, 0, 0, pb, s, &s, BCRYPT_BLOCK_PADDING)))
|
|
{
|
|
if (pb)
|
|
{
|
|
DbgPrint("Encrypt: %x -> %x\r\n", cb, s);
|
|
status = I_CreateAsmSC(psz, pb, s);
|
|
break;
|
|
}
|
|
|
|
if (!(pb = new UCHAR[s]))
|
|
{
|
|
status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pb)
|
|
{
|
|
delete[] pb;
|
|
}
|
|
|
|
BCryptDestroyKey(hKey);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
return I_CreateAsmSC(to, pv, cb);
|
|
}
|
|
|
|
NTSTATUS CreateZipAsmSC(PCWSTR to, PVOID pv, ULONG cb)
|
|
{
|
|
COMPRESSOR_HANDLE CompressorHandle;
|
|
if (CreateCompressor(COMPRESS_ALGORITHM_MSZIP, 0, &CompressorHandle))
|
|
{
|
|
ULONG dwError;
|
|
SIZE_T CompressedDataSize;
|
|
|
|
switch (dwError = BOOL_TO_ERROR(Compress(CompressorHandle, 0, cb, 0, 0, &CompressedDataSize)))
|
|
{
|
|
case NOERROR:
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
if (PBYTE pb = new BYTE[CompressedDataSize])
|
|
{
|
|
if (Compress(CompressorHandle, pv, cb, pb, CompressedDataSize, &CompressedDataSize))
|
|
{
|
|
DbgPrint("Compress:%x >> %x [%u%%]\r\n", cb, CompressedDataSize, (CompressedDataSize * 100) / cb);
|
|
dwError = CreateAsmSC(to, pb, (ULONG)CompressedDataSize);
|
|
}
|
|
else
|
|
{
|
|
dwError = GetLastError();
|
|
}
|
|
|
|
delete[] pb;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
CloseCompressor(CompressorHandle);
|
|
|
|
return HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
NTSTATUS CreateExeSC(PCWSTR pwzFileName, PVOID Base, ULONG cb, PVOID ImageBase)
|
|
{
|
|
struct PE
|
|
{
|
|
union {
|
|
UCHAR pad[0x200];
|
|
struct
|
|
{
|
|
IMAGE_DOS_HEADER idh;
|
|
IMAGE_NT_HEADERS inth;
|
|
IMAGE_SECTION_HEADER ish;
|
|
};
|
|
};
|
|
UCHAR text[];
|
|
|
|
void* operator new(size_t s, ULONG cb)
|
|
{
|
|
return RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, s + cb);
|
|
}
|
|
|
|
void operator delete(void* p)
|
|
{
|
|
RtlFreeHeap(GetProcessHeap(), 0, p);
|
|
}
|
|
};
|
|
|
|
if (PE* pe = new(cb) PE)
|
|
{
|
|
PIMAGE_NT_HEADERS pinth = RtlImageNtHeader(ImageBase);
|
|
|
|
memcpy(&pe->idh, ImageBase, sizeof(IMAGE_DOS_HEADER));
|
|
memcpy(&pe->inth, pinth, sizeof(IMAGE_NT_HEADERS));
|
|
|
|
pe->idh.e_lfanew = sizeof(IMAGE_DOS_HEADER);
|
|
pe->inth.FileHeader.NumberOfSections = 1;
|
|
pe->inth.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
|
|
pe->inth.FileHeader.Characteristics &= ~IMAGE_FILE_DLL;
|
|
|
|
pe->inth.OptionalHeader.AddressOfEntryPoint = 0x1000;
|
|
pe->inth.OptionalHeader.SizeOfCode = cb;
|
|
pe->inth.OptionalHeader.BaseOfCode = 0x1000;
|
|
pe->inth.OptionalHeader.SizeOfInitializedData = 0;
|
|
pe->inth.OptionalHeader.SizeOfUninitializedData = 0;
|
|
pe->inth.OptionalHeader.SectionAlignment = 0x1000;
|
|
pe->inth.OptionalHeader.FileAlignment = 0x200;
|
|
pe->inth.OptionalHeader.SizeOfImage = ((cb + 0x1FFF) & ~0xFFF);
|
|
pe->inth.OptionalHeader.SizeOfHeaders = sizeof(PE);
|
|
pe->inth.OptionalHeader.CheckSum = 0;
|
|
pe->inth.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
|
|
RtlZeroMemory(pe->inth.OptionalHeader.DataDirectory, sizeof(pe->inth.OptionalHeader.DataDirectory));
|
|
|
|
memcpy(pe->ish.Name, ".text\0\0", IMAGE_SIZEOF_SHORT_NAME);
|
|
pe->ish.Misc.VirtualSize = cb;
|
|
pe->ish.VirtualAddress = 0x1000;
|
|
pe->ish.SizeOfRawData = cb;
|
|
pe->ish.PointerToRawData = sizeof(PE);
|
|
pe->ish.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
|
|
|
|
memcpy(pe->text, Base, cb);
|
|
|
|
NTSTATUS status = SaveToFile(pwzFileName, pe, sizeof(PE) + cb);
|
|
|
|
delete pe;
|
|
|
|
DbgPrint("CreateExeSC(%ws)=%x\r\n", pwzFileName, status);
|
|
|
|
return status;
|
|
}
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
NTSTATUS NTAPI PrepareSC(PVOID Base, ULONG cb, PVOID ImageBase)
|
|
{
|
|
if (IsDebuggerPresent())
|
|
{
|
|
return VirtualProtect(Base, cb, PAGE_EXECUTE_READWRITE, &cb) ? 0 : RtlGetLastNtStatus();
|
|
}
|
|
|
|
DbgPrint("PrepareSC(%p, %x, <%ws>)\r\n", Base, cb, GetCommandLineW());
|
|
|
|
//*map*imp[*bin*[?[password?]]asm*exe]
|
|
|
|
if (PWSTR psz = wcschr(GetCommandLineW(), '*'))
|
|
{
|
|
PWSTR pczMap = ++psz;
|
|
|
|
if (psz = wcschr(psz, '*'))
|
|
{
|
|
*psz++ = 0;
|
|
PWSTR pczImp = psz, pczBin = 0, pczAsm = 0, pczExe = 0;
|
|
|
|
if (psz = wcschr(psz, '*'))
|
|
{
|
|
*psz++ = 0;
|
|
pczBin = psz;
|
|
|
|
if (psz = wcschr(psz, '*'))
|
|
{
|
|
*psz++ = 0;
|
|
pczAsm = psz;
|
|
|
|
if (psz = wcschr(psz, '*'))
|
|
{
|
|
*psz++ = 0;
|
|
pczExe = psz;
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS status = ProcessIAT(pczImp, pczMap, (ULONG_PTR)Base + cb);
|
|
|
|
if (0 <= status)
|
|
{
|
|
if (pczBin && *pczBin)
|
|
{
|
|
status = SaveToFile(pczBin, Base, cb);
|
|
}
|
|
|
|
if (0 <= status)
|
|
{
|
|
if (pczAsm && *pczAsm)
|
|
{
|
|
status = '?' == *pczAsm ? CreateZipAsmSC(pczAsm + 1, Base, cb) : CreateAsmSC(pczAsm, Base, cb);
|
|
}
|
|
|
|
if (0 <= status)
|
|
{
|
|
if (pczExe && *pczExe)
|
|
{
|
|
status = CreateExeSC(pczExe, Base, cb, ImageBase);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return PrintError(status);
|
|
}
|
|
}
|
|
|
|
return PrintError(STATUS_INVALID_PARAMETER);
|
|
} |