[2024]基于C++的混淆壳(一) huoji 壳 2024-03-05 295 次浏览 0 次点赞 花了点时间造了个轮子,C++的混淆壳,把步骤分享给大家 ### 做壳步骤 1. 创建区段 2. 遍历所有指令 3. 识别指令类型 <-先说到这里 4. 加花/混淆/处理跳转表 5. 处理原来老的区段 6. 处理PE入口点 7. 处理PE头 ### 创建区段 无需多言,PE基本结构,在内存建立一个壳段.这部分关键点是注意对齐,否则就跑不了了 ```cpp PIMAGE_SECTION_HEADER pe64::create_section(std::string name, uint32_t size, uint32_t characteristic) { if (name.length() > IMAGE_SIZEOF_SHORT_NAME) throw std::runtime_error( "section name can't be longer than 8 characters!"); PIMAGE_FILE_HEADER file_header = &this->get_nt()->FileHeader; PIMAGE_OPTIONAL_HEADER optional_header = &this->get_nt()->OptionalHeader; PIMAGE_SECTION_HEADER section_header = (PIMAGE_SECTION_HEADER)IMAGE_FIRST_SECTION(this->get_nt()); PIMAGE_SECTION_HEADER last_section = §ion_header[file_header->NumberOfSections - 1]; PIMAGE_SECTION_HEADER new_section_header = nullptr; new_section_header = (PIMAGE_SECTION_HEADER)((PUCHAR)(&last_section->Characteristics) + 4); memcpy(new_section_header->Name, name.c_str(), name.length()); new_section_header->Misc.VirtualSize = align(size + sizeof(uint32_t) + 1, optional_header->SectionAlignment); new_section_header->VirtualAddress = align(last_section->VirtualAddress + last_section->Misc.VirtualSize, optional_header->SectionAlignment); new_section_header->SizeOfRawData = align(size + sizeof(uint32_t) + 1, optional_header->FileAlignment); new_section_header->PointerToRawData = align(last_section->PointerToRawData + last_section->SizeOfRawData, optional_header->FileAlignment); new_section_header->Characteristics = characteristic; new_section_header->PointerToRelocations = 0x0; new_section_header->PointerToLinenumbers = 0x0; new_section_header->NumberOfRelocations = 0x0; new_section_header->NumberOfLinenumbers = 0x0; file_header->NumberOfSections += 1; uint32_t old_size = optional_header->SizeOfImage; optional_header->SizeOfImage = align(optional_header->SizeOfImage + size + sizeof(uint32_t) + 1 + sizeof(IMAGE_SECTION_HEADER), optional_header->SectionAlignment); optional_header->SizeOfHeaders = align(optional_header->SizeOfHeaders + sizeof(IMAGE_SECTION_HEADER), optional_header->FileAlignment); std::vector new_buffer; new_buffer.resize(optional_header->SizeOfImage); memset(new_buffer.data(), 0, optional_header->SizeOfImage); memcpy(new_buffer.data(), this->buffer.data(), old_size); this->buffer = new_buffer; return this->get_section(name); } ``` ### 遍历所有指令 我用的是capstone,有个坑,一定要给 ``` cs_option(capstone_handle, CS_OPT_SKIPDATA, CS_OPT_ON); ``` CS_OPT_SKIPDATA设置为ON 否则你复制TEXT段遇到识别不了的指令就拉了. 然后就是正常的复制代码 代码 ``` disasmCount = cs_disasm( capstone_handle, reinterpret_cast(function->start_address), function->size, (uint64_t)function->start_address, 0, &insn); if (disasmCount == 0) { break; } auto currentAddress = sectionBase + usedSectionOffset; function->inDuckSectionAddress = (uint64_t)currentAddress; for (size_t index = 0; index < disasmCount; index++) { const auto code = &insn[index]; currentAddress = sectionBase + usedSectionOffset; memcpy(currentAddress, code->bytes, code->size); usedSectionOffset += code->size; function->inDuckSectionSize += code->size; functionSize += code->size; //function->inDuckSectionSize += code->size; //printf("address: 0x%llx | size: %d code: %s %s \n", code->address, code->size, code->mnemonic, code->op_str); sourceFunctionInsn.build_ins.push_back({ .cs_ins = code, .functionAddress = function->start_address, .codeSectionAddress = code->address, .newSectionAddress = (uint64_t)currentAddress, .insSize = code->size, }); ``` ### 识别指令类型 这里是为了后续处理重定向以及混淆用的,这部分我花的时间是最多的,因为要处理非常多的指令类型,你的壳出现bug也大概率是出现在这里. ```cpp // 之所以分开是因为以后要特殊处理每一种指令(混淆) if (isJmp(code)) { _jmpTableDetails jmpItem; jmpItem.cs_ins = code; if (code->detail->x86.operands[0].type == X86_OP_IMM) { jmpItem.callType = _callType::kIMM; } else if (code->detail->x86.operands[0].type == X86_OP_MEM) { jmpItem.callType = _callType::kMem; } else { continue; } if (jmpItem.callType == _callType::kIMM) { jmpItem.calladdress = code->detail->x86.operands[0].imm; } else if (code->detail->x86.operands[0].type == X86_OP_MEM && code->detail->x86.operands[0].mem.base == X86_REG_RIP) { jmpItem.calladdress = *( uint64_t*)(code->detail->x86.operands[0].mem.disp + code->address + code->size); jmpItem.preReadAddress = code->detail->x86.operands[0].mem.disp + code->address + code->size; } else { continue; } jmpItem.inNewSectoinAddress = (uint64_t)currentAddress; jmpItem.nextAddress = code->address + code->size; jmpItem.insSize = code->size; jmpItem.address = code->address; jmpItem.offset = code->address - jmpItem.calladdress; jmpItem.isFixed = false; jmpTable.push_back(jmpItem); continue; } else if (isCall(code)) { _callTableDetails callItem; callItem.cs_ins = code; if (code->detail->x86.operands[0].type == X86_OP_IMM) { callItem.callType = _callType::kIMM; } else if (code->detail->x86.operands[0].type == X86_OP_MEM) { callItem.callType = _callType::kMem; } else { continue; } if (callItem.callType == _callType::kIMM) { callItem.calladdress = code->detail->x86.operands[0].imm; } else if (code->detail->x86.operands[0].type == X86_OP_MEM && code->detail->x86.operands[0].mem.base == X86_REG_RIP) { callItem.calladdress = *( uint64_t*)(code->detail->x86.operands[0].mem.disp + code->address + code->size); callItem.preReadAddress = code->detail->x86.operands[0].mem.disp + code->address + code->size; } else { continue; } callItem.inNewSectoinAddress = (uint64_t)currentAddress; callItem.nextAddress = code->address + code->size; callItem.insSize = code->size; callItem.address = code->address; callItem.offset = code->address - callItem.calladdress; callItem.isFixed = false; callTable.push_back(callItem); continue; } // 检查是不是lea/mov/cmp /* if (code->id != X86_INS_LEA && code->id != X86_INS_MOV && code->id != X86_INS_CMP && code->id != X86_INS_MOVZX) { continue; }*/ _otherNeedFixInsDetails otherIns; // 栈内存操作 if (code->detail->x86.sib_base == X86_REG_RSP) { continue; } if (code->detail->x86.operands[0].type == X86_OP_IMM) { otherIns.callType = _callType::kIMM; } else if (code->detail->x86.operands[0].type == X86_OP_MEM) { otherIns.callType = _callType::kMem; } else if (code->detail->x86.operands[0].type == X86_OP_REG) { otherIns.callType = _callType::kReg; } else { continue; } if (otherIns.callType == _callType::kIMM) { otherIns.calladdress = code->detail->x86.operands[0].imm; } else if (code->detail->x86.operands[0].type == X86_OP_MEM && code->detail->x86.operands[0].mem.base == X86_REG_RIP) { otherIns.preReadAddress = code->detail->x86.operands[0].mem.disp + code->address + code->size; auto [readSuccess, readAddr] = SafeRedPtr(otherIns.preReadAddress); if (readSuccess == false) { continue; } otherIns.calladdress = readAddr; } else if (otherIns.callType == _callType::kReg && code->detail->x86.operands[1].type == X86_OP_MEM && code->detail->x86.operands[1].mem.base == X86_REG_RIP) { otherIns.preReadAddress = code->detail->x86.operands[1].mem.disp + code->address + code->size; otherIns.calladdress = *(uint64_t*)(otherIns.preReadAddress); } else { continue; } otherIns.cs_ins = code; otherIns.address = code->address; otherIns.inNewSectoinAddress = (uint64_t)currentAddress; otherIns.isFixed = false; otherIns.insSize = code->size; otherInsTable.push_back(otherIns); continue; } ``` ### 未完待续 未完待续... 本文由 huoji 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。 点赞 0
还不快抢沙发