feat: IatObfuscation option, Section Name Randomizing, New Section Logic

- Adding a new option on obfuscator for IAT obfuscation support.
- Adding a new logic to randomize section names.
- Adding the initial logic to add a new section in the PE file. and writing some ideas and some things to be able to continue the logic in a correct way.
This commit is contained in:
keowu
2025-05-24 22:03:30 -03:00
parent ee3025b942
commit 43b50dffe4
4 changed files with 109 additions and 2 deletions

View File

@@ -2,8 +2,9 @@
class RyujinObfuscatorConfig {
public:
bool m_isRandomSection; // Randomize the name of the new section with the processed code -> Ryujin standard
bool m_isRandomSection; // Randomize the name of the new section with the processed code -> ".Ryujin" standard
bool m_isVirtualized; // Virtualize the code [Try as much as possible]
bool m_isIatObfuscation; //Process IAT Obfuscation
bool m_isJunkCode; // Insert junk code to confuse
bool m_isIgnoreOriginalCodeRemove; // Do not remove the original code after processing (replace the original instructions with NOPs)
std::vector<std::string> m_strProceduresToObfuscate; // Names of the procedures to obfuscate

View File

@@ -97,7 +97,12 @@ bool Ryujin::run(const RyujinObfuscatorConfig& config) {
if (it == config.m_strProceduresToObfuscate.end()) continue;
std::printf("[WORKING ON]: %s\n", proc.name.c_str());
std::printf(
"[WORKING ON]: %s\n",
proc.name.c_str()
);
// Is a valid procedure ?
if (proc.size == 0) {
@@ -125,11 +130,30 @@ bool Ryujin::run(const RyujinObfuscatorConfig& config) {
RyujinBasicBlockerBuilder rybb(ZYDIS_MACHINE_MODE_LONG_64, ZydisStackWidth_::ZYDIS_STACK_WIDTH_64);
proc.basic_blocks = rybb.createBasicBlocks(ucOpcodes, proc.size, proc.address);
//Is time to obfuscate ?
if (config.m_isVirtualized) todoAction();
if (config.m_isIatObfuscation) todoAction();
if (config.m_isJunkCode) todoAction();
//TODO: Custom passes support
//Clean up opcodes
delete[] ucOpcodes;
}
//More obfuscation
if (config.m_isIgnoreOriginalCodeRemove) todoAction();
//Add section
char chSectionName[8]{ '.', 'R', 'y', 'u', 'j', 'i', 'n', '\0' };
if (config.m_isRandomSection) RyujinUtils::randomizeSectionName(chSectionName);
RyujinUtils::AddNewSection(m_mappedPE, m_szFile, chSectionName);
//Fix relocations
//Save output file
}
void Ryujin::listRyujinProcedures() {

View File

@@ -20,6 +20,8 @@ private:
BOOL m_isInitialized;
std::vector<RyujinProcedure> m_ryujinProcedures;
bool todoAction() { return FALSE; }
public:
Ryujin(const std::string& strInputFilePath, const std::string& strPdbFilePath, const std::string& strOutputFilePath);
bool run(const RyujinObfuscatorConfig& config);

View File

@@ -3,6 +3,8 @@
#include <memory>
#include <Windows.h>
#define ALIGN_UP(value, alignment) ((value + alignment - 1) & ~(alignment - 1))
namespace RyujinUtils {
inline std::pair<BOOL, uintptr_t> MapPortableExecutableFileIntoMemory(const std::string& m_strInputFilePath, std::shared_ptr<unsigned char>& mappedPE) {
@@ -121,5 +123,83 @@ namespace RyujinUtils {
return std::make_pair(TRUE, szFile.QuadPart);
}
inline BOOL AddNewSection(std::shared_ptr<unsigned char>& mappedPE, uintptr_t szFile, char chSectionName[8]) {
auto ucModifiedPeMap = new unsigned char[szFile] { 0 };
std::memcpy(
ucModifiedPeMap,
mappedPE.get(),
szFile
);
auto dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(ucModifiedPeMap);
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
delete[] ucModifiedPeMap;
return FALSE;
}
auto ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(ucModifiedPeMap + dosHeader->e_lfanew);
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) {
delete[] ucModifiedPeMap;
return FALSE;
}
auto sectionTableSize = ntHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if (dosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS) + sectionTableSize > ntHeaders->OptionalHeader.SizeOfHeaders) {
//No space to insert a new section on this PE FILE :(
delete[] ucModifiedPeMap;
return FALSE;
}
//Adding the new section
IMAGE_SECTION_HEADER newSection{ 0 };
std::memcpy(
newSection.Name,
chSectionName,
sizeof(chSectionName)
);
auto imgLastSection = IMAGE_FIRST_SECTION(ntHeaders) + (ntHeaders->FileHeader.NumberOfSections - 1);
newSection.VirtualAddress = ALIGN_UP(
imgLastSection->VirtualAddress + imgLastSection->Misc.VirtualSize,
ntHeaders->OptionalHeader.SectionAlignment
);
newSection.PointerToRawData = ALIGN_UP(
imgLastSection->PointerToRawData + imgLastSection->SizeOfRawData,
ntHeaders->OptionalHeader.FileAlignment
);
newSection.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
//Return the following in order to put data and calculate relocs:
//newSection.VirtualAddress
//newSection.Misc.VirtualSize = size of new code;
//newSection.SizeOfRawData = ALIGN_UP(size of new code, ntHeaders->OptionalHeader.FileAlignment);
//Maybe is better wrap this things in a full new class ??
return FALSE;
}
inline void randomizeSectionName(char* chName) {
const char charset[] { "abcdefghijklmnopqrstuvwxyz" };
for (size_t i = 0; i < 8 - 1; ++i) chName[i] = charset[std::rand() % (sizeof(charset) - 1)];
chName[8 - 1] = '\0';
}
};