Skip to content

Commit

Permalink
Merge pull request #6 from buzzer-re/dev
Browse files Browse the repository at this point in the history
v1.3
  • Loading branch information
buzzer-re authored Jul 25, 2023
2 parents 666c257 + e14c48e commit 1befdb5
Show file tree
Hide file tree
Showing 22 changed files with 418 additions and 83 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ jobs:
run: |
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
# Dirty hack
git checkout a325228200d7f229f3337e612e0077f2a5307090
.\bootstrap-vcpkg.bat
# Install vcpkg dependencies
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
run: |
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
git checkout a325228200d7f229f3337e612e0077f2a53
.\bootstrap-vcpkg.bat
# Install vcpkg dependencies
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,3 @@ Please open an issue or pull request for any changes you would like to make.

This cool mascot image was inspired on Bleach and generated by [Dall-E](https://openai.com/product/dall-e-2).


1 change: 1 addition & 0 deletions Shinigami/Ichigo/Mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct Memory
&& cAlloc == other.cAlloc;
}

ULONG_PTR IP; // If this memory is being executed, this value holds the offset of the current execution, must be set manually
uint8_t* Addr;
ULONG_PTR End;
SIZE_T Size;
Expand Down
160 changes: 154 additions & 6 deletions Shinigami/Ichigo/PEDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,30 +60,179 @@ Memory* PEDumper::DumpPE(ULONG_PTR* Address)
return mem;
}


PIMAGE_DOS_HEADER PEDumper::FindPE(Memory* Mem)
{
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
MEMORY_BASIC_INFORMATION mbi;

for (uint8_t* Curr = reinterpret_cast<uint8_t*>(Mem->Addr); (ULONG_PTR)Curr < Mem->End; Curr++)
for (uint8_t* Curr = reinterpret_cast<uint8_t*>(Mem->Addr); (ULONG_PTR)Curr < Mem->End - sizeof(IMAGE_DOS_HEADER); Curr++)
{
pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(Curr);

if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
pNtHeader = reinterpret_cast<PIMAGE_NT_HEADERS>((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
if ((ULONG_PTR)pNtHeader <= Mem->End - sizeof(pNtHeader) &&
pNtHeader->Signature == IMAGE_NT_SIGNATURE)

if ((ULONG_PTR)pNtHeader <= Mem->End)
{
return pDosHeader;
if (!VirtualQuery((LPCVOID)pNtHeader, &mbi, 0x1000))
continue;

if (pNtHeader->Signature == IMAGE_NT_SIGNATURE)
return pDosHeader;
}
}
}
// Search for detached headers
return PEDumper::HeuristicSearch(Mem);
}

PIMAGE_DOS_HEADER PEDumper::HeuristicSearch(Memory* Mem)
{
PipeLogger::LogInfo(L"Starting heuristic scan for detached headers at 0x%p...", Mem->Addr);
// Search for NT headers
// If found, validated sections offset and if it has code
PIMAGE_NT_HEADERS pNtHeader;
MEMORY_BASIC_INFORMATION mbi;

for (uint8_t* Curr = reinterpret_cast<uint8_t*>(Mem->Addr); (ULONG_PTR)Curr < Mem->End - sizeof(IMAGE_NT_HEADERS); Curr++)
{
pNtHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(Curr);
if (IsValidNT(pNtHeader))
{
// So far so good
PipeLogger::LogInfo(L"Found possible NT header at 0x%p", Curr);

if (!VirtualQuery((LPCVOID)&pNtHeader->OptionalHeader, &mbi, sizeof(IMAGE_OPTIONAL_HEADER)))
continue;

if ((ULONG_PTR) Mem->Addr + pNtHeader->OptionalHeader.AddressOfEntryPoint == Mem->IP)
{
// We are at this executable entrypoint, rebuild the DOS header
if (Mem->Addr - Curr <= sizeof(IMAGE_DOS_HEADER))
{
// We dont have space
// TODO: Resize Mem struct
}

PIMAGE_DOS_HEADER DosHdr = RebuildDOSHeader(Mem, (ULONG_PTR) Curr);
if (DosHdr != nullptr)
{
PipeLogger::LogInfo(L"DOS header rebuilded!");
return DosHdr;
}
}
else
{
// Parse each section in this possible header, verify if is at a valided the section struct data (permissions, offset...)
// If looks valid verify if the current EIP is between some of them
// If it is, log that, else log that it found valid sections mapped but the code might be hidden somehow
// Save the current NT address and proceed to the brute-force part of this code, if the brute-force fail
// use this saved NT address and tell the user
IMAGE_SECTION_HEADER* sectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
bool Invalid = true;
bool IPInBetween = false;
ULONG_PTR VirtualMemAddr;
for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++, sectionHeader++) {
// Invalid memory area
if (Utils::IsReadWritable((ULONG_PTR*)sectionHeader) == INVALID_MEMORY_AREA) {
Invalid = true;
break;
}

VirtualMemAddr = sectionHeader->VirtualAddress + (ULONG_PTR)Mem->Addr;
// Check if there is any overflow here
if (sectionHeader->PointerToRawData + sectionHeader->SizeOfRawData + (ULONG_PTR) Mem->Addr >= Mem->End ||
sectionHeader->VirtualAddress + sectionHeader->Misc.VirtualSize + (ULONG_PTR) Mem->Addr >= Mem->End)
{
Invalid = true;
break;
}

// Check if the Instruction pointer is between this image
if (Mem->IP >= VirtualMemAddr && Mem->IP <= VirtualMemAddr + sectionHeader->Misc.VirtualSize)
IPInBetween = true;

}

if (Invalid)
continue;

if (!Invalid && IPInBetween)
{
PipeLogger::LogInfo(L"Possible NT found at 0x%p! Trying to rebuild...", pNtHeader);
PIMAGE_DOS_HEADER DosHdr = RebuildDOSHeader(Mem, (ULONG_PTR)Curr);
if (DosHdr != nullptr)
{
PipeLogger::LogInfo(L"DOS header rebuilded!");
return DosHdr;
}
}
}
}
}


// We failed to search detached DOS headers
// Search for common sections names such: .text, .data, .rdata
// If found, walk back and try to rebuild the DOS headers and NT headers



// We failed, return nullptr

return nullptr;
}


// Verify NT headers fields to validate if is valid
BOOL PEDumper::IsValidNT(PIMAGE_NT_HEADERS pNtHeader)
{
return pNtHeader->Signature == IMAGE_NT_SIGNATURE &&
(
pNtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_UNKNOWN ||
pNtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE ||
pNtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ||
pNtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI ||
pNtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_OS2_CUI ||
pNtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_POSIX_CUI ||
pNtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ||
pNtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_UNKNOWN
)
&&
(
pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC
);
}


PIMAGE_DOS_HEADER PEDumper::RebuildDOSHeader(Memory* Mem, ULONG_PTR NtHeaderOffset)
{
// This function rely in the fact that we already have space allocated, if there is no space in the beginning of this file
// the memory must be resized calling the mem.IncreaseSize(sizeof(IMAGE_DOS_HEADER), SHIFT_BEGIN) before call this function
// Check if we have space
DWORD OldProt;

if (Mem->Size < sizeof(IMAGE_DOS_HEADER) || NtHeaderOffset >= Mem->End) return nullptr;

PIMAGE_DOS_HEADER DosHdr = reinterpret_cast<PIMAGE_DOS_HEADER>(Mem->Addr);
// Rebuild basic fields only

if (!VirtualProtect(Mem->Addr, sizeof(IMAGE_DOS_HEADER), PAGE_READWRITE, &OldProt))
return nullptr;

DosHdr->e_magic = IMAGE_DOS_SIGNATURE;
DosHdr->e_lfanew = NtHeaderOffset - (ULONG_PTR) DosHdr;

VirtualProtect(Mem->Addr, sizeof(IMAGE_DOS_HEADER), OldProt, &OldProt);
FixPESections(Mem);

return DosHdr;
}


SIZE_T PEDumper::GetPESize(PIMAGE_NT_HEADERS pNTHeader)
{
// Get the first section header
Expand Down Expand Up @@ -128,7 +277,6 @@ VOID PEDumper::FixPESections(Memory* mem)
if (Utils::IsReadWritable((ULONG_PTR*)pNtHeader) == INVALID_MEMORY_AREA) {
return;
}

IMAGE_SECTION_HEADER* sectionHeaders = IMAGE_FIRST_SECTION(pNtHeader);

// Modify the section headers
Expand Down
4 changes: 3 additions & 1 deletion Shinigami/Ichigo/PEDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ namespace PEDumper
Memory* FindRemotePE(HANDLE hProcess, const Memory* mem);
Memory* DumpPE(ULONG_PTR* Address);
PIMAGE_DOS_HEADER FindPE(Memory* Mem);

PIMAGE_DOS_HEADER HeuristicSearch(Memory* Mem);
PIMAGE_DOS_HEADER RebuildDOSHeader(Memory* Mem, ULONG_PTR NtHeaderOffset);
BOOL IsValidNT(PIMAGE_NT_HEADERS pNtHeader);
SIZE_T GetPESize(PIMAGE_NT_HEADERS pNTHeader);
VOID FixPESections(Memory* pNTHeader);
};
Expand Down
1 change: 0 additions & 1 deletion Shinigami/Ichigo/ProcessUnhollow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ NTSTATUS WINAPI Unhollow::hkNtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID*
{
NTSTATUS status = ProcessInformation.Win32Pointers.NtAllocateVirtualMemory(ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect);
DWORD ProcessPID = GetProcessId(ProcessHandle);

if (ProcessPID == Unhollow::ProcessInformation.pi.dwProcessId && NT_SUCCESS(status))
{
if (BaseAddress == nullptr)
Expand Down
Loading

0 comments on commit 1befdb5

Please sign in to comment.