unicorn icon indicating copy to clipboard operation
unicorn copied to clipboard

UC_ERR_MAP issue when trying to emulate

Open user1342234 opened this issue 3 years ago • 3 comments

First of all, sorry for the terrible code.

Whenever I try to emulate my obfuscated driver it fails at uc_emu_start with UC_ERR_MAP. I get all success return codes on: uc_mem_map and uc_mem_write but when I call uc_emu_start ; I get the UC_ERR_MAP error. So, I added a hook on the error code to see what address it was writing to and I found that it was: 0xff8. I don't understand why it is writing to this address because I put 0x1000 as my base address (std::uint64_t BASE_ADDRESS = 0x1000;) which is then used at uc_emu_start. Any help would be appreciated.

I was reading through the source code and I came to the conclusion that UC_ERR_MAP means that the mapped region overlaps with another region. The only other region I'm allocating is the one for my driver which i've listed the source to below. Everything in that specific source file works as I can disassemble the code and print it easily using capstone but I can't emulate it using unicorn for some reason. Also, my driver size is: 11.4 MB (11,990,544 bytes)

I also noticed on the photo below that the data that is being written is inside the RCX register. So it is correctly reading the registers I guess? image

Main source file.

`// EMU.cpp : This file contains the 'main' function. Program execution begins and ends there. // #include <unicorn.h> #include "capstone/capstone.h" #include #include #include #include #include "PE.h" #include "BasicBlock.h" #include "Optimizations.h" #include "CCapstoneHelper.h" static bool hook_mem_invalid(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data) { switch (type) { default: // return false to indicate we want to stop emulation return false; case UC_MEM_WRITE_UNMAPPED: printf(">>> Missing memory is being WRITE at 0x%" PRIx64 ", data size = %u, data value = 0x%" PRIx64 "\n", address, size, value); // map this memory in with 2MB in size uc_mem_map(uc, 0xaaaa0000, 2 * 1024 * 1024, UC_PROT_ALL); // return true to indicate we want to continue return true; } }

#define ADDRESS 0x1000

int64_t rax = 0x71f3029efd49d41d; int64_t rbx = 0xd87b45277f133ddb; int64_t rcx = 0xab40d1ffd8afc461; int64_t rdx = 0x919317b4a733f01; int64_t rsi = 0x4c24e753a17ea358; int64_t rdi = 0xe509a57d2571ce96; int64_t r8 = 0xea5b108cc2b9ab1f; int64_t r9 = 0x19ec097c8eb618c1; int64_t r10 = 0xec45774f00c5f682; int64_t r11 = 0xe17e9dbec8c074aa; int64_t r12 = 0x80f86a8dc0f6d457; int64_t r13 = 0x48288ca5671c5492; int64_t r14 = 0x595f72f6e4017f6e; int64_t r15 = 0x1efd97aea331cccc;

int64_t rsp = 0x1000;

int main() { try { // UNICORN uc_engine* uc; uc_err err;

    // CAPSTONE
    csh handle{};
    cs_insn* insn;
    //size_t count; 
    std::queue<uint64_t> Q;
    std::map<uint64_t, bool> seen;
    std::uint64_t BASE_ADDRESS = 0x1000;
    // 0xaaaa0000;

    bool error;

#define MEGABYTES_TO_MAP 15

    std::cout << "[+] Starting emulation..." << std::endl;
    if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) {
        throw std::runtime_error("cs_open failed");
    }

    err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc);
    if (err != UC_ERR_OK) {
        throw std::runtime_error("uc_open failed");
    }
    err = uc_mem_map(uc, BASE_ADDRESS, 0x1000, UC_PROT_ALL); // right click scroll up. ERR_MEM_MAP MEANS THAT MEMORY OVERLAPS ALREADY MAPPED REGION POSSIBLE CAPSTONES? OR THE OTHER MEMORY REGION ALLOCATED BY THIS BIG FILE
    if (err) {
        throw std::runtime_error("uc_mem_map failed");
    }

  



    cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);

   
 
    insn = cs_malloc(handle);
    std::cout << "[+] Finding driver entry point..." << std::endl;
   PE::CPe pe = PE::CPe::CPe("C:\\Program Files (x86)\\Drv\\Drv.sys");


   std::cout << "[+] Found: " << std::hex << pe.get_entry_point_address_relative_to_mapped_file() << std::endl;

   std::cout << "[+] Starting emulation..." << std::endl;
   BasicBlock::CBasicBlock block_buffer{};
   BasicBlock::_basic_block basic_block{};
   basic_block.start_address = pe.get_entry_point_address_relative_to_mapped_file();
//   BASE_ADDRESS += pe.get_entry_point_file_offset();
    const std::uint8_t* addr = (std::uint8_t*) basic_block.start_address;
  
   // we are at entry point. Start emulation until we reach end of basic block?
   // At entrypoint, set start of basic block to entry point address.
   // Emulate until we reach a JUMP instruction
    std::cout << "[+] Removing anti-disassembly..." << std::endl;
    Optimizations::COptimizations optimizations;
    std::uint8_t anti_d_pattern[] = {0xEB, 0xFF, 0x64, 0x24, 0x08};
    std::uint64_t num_of_bytes_fixed = optimizations.remove_antidisassembly(anti_d_pattern, sizeof(anti_d_pattern), pe);
   
    uint64_t target = 0;
   size_t code_size = 0x1000;
   
   CapstoneHelper::CCapstoneHelper capstone_helper_obj;


   uc_hook hook;
   err = uc_hook_add(uc, &hook, UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL, 1, 0);
  


   uc_reg_write(uc, UC_X86_REG_RSP, &rsp);

   uc_reg_write(uc, UC_X86_REG_RAX, &rax);
   uc_reg_write(uc, UC_X86_REG_RBX, &rbx);
   uc_reg_write(uc, UC_X86_REG_RCX, &rcx);
   uc_reg_write(uc, UC_X86_REG_RDX, &rdx);
   uc_reg_write(uc, UC_X86_REG_RSI, &rsi);
   uc_reg_write(uc, UC_X86_REG_RDI, &rdi);
   uc_reg_write(uc, UC_X86_REG_R8, &r8);
   uc_reg_write(uc, UC_X86_REG_R9, &r9);
   uc_reg_write(uc, UC_X86_REG_R10, &r10);
   uc_reg_write(uc, UC_X86_REG_R11, &r11);
   uc_reg_write(uc, UC_X86_REG_R12, &r12);
   uc_reg_write(uc, UC_X86_REG_R13, &r13);
   uc_reg_write(uc, UC_X86_REG_R14, &r14);
   uc_reg_write(uc, UC_X86_REG_R15, &r15);










   while (true) {

       std::uint64_t prev_base_address = BASE_ADDRESS;
      while (cs_disasm_iter(handle, &addr, &code_size, &BASE_ADDRESS, insn)) {
           if (capstone_helper_obj.is_cs_cflow_ins(insn)) {
               basic_block.end_address = (std::uint64_t)addr;
               break;
           }
           

       }

       
       std::uint32_t error;
       // write code and then some into memory
       //uc_mem_map(uc, prev_base_address, MEGABYTES_TO_MAP * 1024 * 1024, UC_PROT_ALL);
      // if (uc_mem_map(uc, BASE_ADDRESS, MEGABYTES_TO_MAP * 1024 * 1024, UC_PROT_ALL) != UC_ERR_OK) {
      
           err = uc_mem_write(uc, prev_base_address, reinterpret_cast<void*>(basic_block.start_address), (basic_block.end_address - basic_block.start_address));
           if (err != UC_ERR_OK) {
              throw std::runtime_error("uc_mem_write failed");
          }
        
          
        // resolve file offset from base_address;
          

           err = uc_emu_start(uc, prev_base_address, prev_base_address + (basic_block.end_address - basic_block.start_address) , 0, 1);
           if (err != UC_ERR_OK) {
               throw std::runtime_error("uc_emu_start failed");
           }



           /* TODO:
           1. Write anti-disassembly remover because capstone won't properly disassemble.
           Anti disassembly byte string: EB FF 64 24 08 (Removing EB byte results in " jmp    QWORD PTR [rsp+0x8]"
           Use file pointer to do operations before we disassemble with capstone.
           2. Add check for control flow instructions (look at PBA)
           */

      
   }

    
   










    
    uc_close(uc);
    cs_close(&handle);
    
}
catch (std::exception& e) {
    std::cout << "Error: " << e.what();
    getchar();
    std::abort();
}

    return 0;

}

// Run program: Ctrl + F5 or Debug > Start Without Debugging menu // Debug program: F5 or Debug > Start Debugging menu

// Tips for Getting Started: // 1. Use the Solution Explorer window to add/manage files // 2. Use the Team Explorer window to connect to source control // 3. Use the Output window to see build output and other messages // 4. Use the Error List window to view errors // 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project // 6. In the future, to open this project again, go to File > Open > Project and select the .sln file `

How I'm mapping my driver.

`PE::CPe::CPe(std::string file_path) { HANDLE hFile = CreateFileA(file_path.data(), GENERIC_ALL, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (!hFile) throw std::runtime_error("CreateFileA Failed");

HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_EXECUTE_READWRITE, 0, 0, NULL);
if (!hMapFile) {
	CloseHandle(hFile);
	throw std::runtime_error("CreateFileMapping Failed");
}


PBYTE pFile = reinterpret_cast<PBYTE>(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0));
if (!pFile) {
	CloseHandle(hFile);
	CloseHandle(hMapFile);
	throw std::runtime_error("MapViewOfFile failed");
}
this->pFileBasePtr = pFile;

PIMAGE_NT_HEADERS64 pNtHdr = ImageNtHeader(pFile);
if (!pFile) {
	CloseHandle(hFile);
	CloseHandle(hMapFile);
	throw std::runtime_error("pNtHdr nullptr");
}

// todo get image_size;
this->image_size = 0xB6F610;
	//0xB50818;
	//0xB5F668;
//this->export_table_address = resolve_address_rva(pNtHdr, pFile, pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
//this->import_table_address = resolve_address_rva(pNtHdr, pFile, pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
this->entry_point_file_offset = pNtHdr->OptionalHeader.AddressOfEntryPoint;
this->entry_point_address = resolve_address_rva(pNtHdr, pFile, pNtHdr->OptionalHeader.AddressOfEntryPoint);

`

user1342234 avatar Jul 15 '22 23:07 user1342234

Formatting messed up, Sorry!

user1342234 avatar Jul 15 '22 23:07 user1342234

Hello, your code & description seems too complex to reproduce. Is it possible to minimize your use case?

wtdcode avatar Jul 23 '22 13:07 wtdcode

Yeah sorry! In the binary I was reversing, I only allocated memory for [rsp + something] but I didn't allocate anything for [rsp - something]. So it was being written to unmapped memory at [rsp - 0x10] . To fix this, I just mapped a lot of memory from my start address and repositioned stack in a way so it was inside that map as well.

user1342234 avatar Jul 25 '22 04:07 user1342234

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 15 days.

github-actions[bot] avatar Sep 23 '22 05:09 github-actions[bot]