/*
* the debug loop, we decrypt and encrypt the exception handler and the
* function that deals with the exceptions
*/
void
debug_loop(void)
{
#if DEBUG
printf("***************************\n");
printf("[DEBUG] Started debug loop!\n");
printf("***************************\n");
#endif
JUNK_CODE1;
uint32_t search;
asm(".att_syntax prefix");
asm __volatile__("nop\n\t"
"call 1f\n\t" // E8 00 00 00 00
"1:\n\t"
"pop %%eax\n\t" // 58
"mov %%eax, %0" // 89 C3
: "=r" (search)
:
:"eax");
asm(".att_syntax prefix");
#if DEBUG
printf("Search is %x %x\n", search, *(uint32_t*)(search+5));
#endif
EVIL_ASM5;
uint8_t iv[8] = "hackersz";
mach_vm_address_t addr = 0;
uint32_t protectSize = 0;
uint32_t functionSize = 0;
uint32_t functionBegin = 0;
volatile uint16_t xorKey = 0x4569;
for (uint32_t i = search; i < search + 0x2000; i++)
{
if ((*(uint16_t*)i ^xorKey) == 0x745D) // 0x3134
{
addr = *(uint32_t*)(i+4);
protectSize = *(uint32_t*)(i+8);
functionSize = *(uint32_t*)(i+12);
#if DEBUG
printf("[DEBUG] Found exception_handler decrypting info at %x . Address:%x Size:%x Function Size:%x!\n", i,
*(uint32_t*)(i+4), *(uint32_t*)(i+8),*(uint32_t*)(i+12));
#endif
break;
}
}
xorKey = 0x1233;
for (uint32_t i = search; i > 0x1000; i--)
{
if ((*(uint16_t*)i ^ xorKey) == 0xF7BA) // 0xe589
{
functionBegin = i - 1;
#if DEBUG
printf("[DEBUG] Found debug_loop() beginning at %x\n", functionBegin);
#endif
break;
}
}
kern_return_t (*mymach_vm_protect)(vm_map_t target_task,mach_vm_address_t address,mach_vm_size_t size,
boolean_t set_maximum,vm_prot_t new_protection);
volatile uint8_t vmprotectsymbol[] = {0x2e,0x22,0x20,0x2b,0x1c,0x35,0x2e,0x1c,0x33,0x31,0x2c,0x37,0x26,0x20,0x37,0x43};
DECRYPT_STRING(16, vmprotectsymbol, 0x43);
mymach_vm_protect = DLSYM_GET(vmprotectsymbol);
while (1)
{
// decrypt exception handler
// build the key
uint8_t key[32];
EVIL_ASM3;
sha2((uint8_t*)functionBegin, functionSize, key, 0);
// build the salt array
uint32_t salt[4];
x86_debug_state32_t debug;
mach_msg_type_number_t count;
thread_state_flavor_t flavor;
flavor = x86_DEBUG_STATE32;
count = x86_DEBUG_STATE32_COUNT;
thread_act_port_array_t thread_list;
mach_msg_type_number_t thread_count;
kern_return_t (*mytask_threads)(task_t target_task,thread_act_array_t *act_list,mach_msg_type_number_t *act_listCnt);
volatile uint8_t taskthreadssymbol[] = {0x20,0x35,0x27,0x3f,0x0b,0x20,0x3c,0x26,0x31,0x35,0x30,0x27,0x54};
DECRYPT_STRING(13,taskthreadssymbol,0x54);
mytask_threads = DLSYM_GET(taskthreadssymbol);
(*mytask_threads)(mach_task_self(), &thread_list, &thread_count);
kern_return_t (*mythread_get_state)(thread_act_t target_act,thread_state_flavor_t flavor,thread_state_t old_state,
mach_msg_type_number_t *old_stateCnt);
volatile uint8_t threadgetstatesymbol[] = {0x37,0x2b,0x31,0x26,0x22,0x27,0x1c,0x24,0x26,0x37,0x1c,0x30,0x37,0x22,0x37,0x26,0x43};
DECRYPT_STRING(17,threadgetstatesymbol,0x43);
mythread_get_state = DLSYM_GET(threadgetstatesymbol);
(*mythread_get_state)(thread_list[0], flavor, (thread_state_t)&debug, &count);
salt[0] = debug.__dr0;
salt[1] = debug.__dr1;
salt[2] = debug.__dr2;
salt[3] = debug.__dr3;
uint8_t *tempKey = malloc(sizeof(salt) + sizeof(key));
memcpy(tempKey, key, sizeof(key));
memcpy(tempKey+sizeof(key), salt, sizeof(salt));
// compute the final salted key
sha2((uint8_t*)tempKey, sizeof(salt) + sizeof(key), key, 0);
free(tempKey);
EVIL_ASM5;
// and now we can finally decrypt
// modify memory protection so we can decrypt and write
kern_return_t kr;
#if DEBUG
printf("[DEBUG] Starting to decrypt exception_handler...\n");
#endif
kr = (*mymach_vm_protect)(mach_task_self(), (mach_vm_address_t)addr, (mach_vm_size_t)protectSize, FALSE, WRITEPROTECTION);
#if DEBUG
EXIT_ON_MACH_ERROR("Failurex", 1);
#endif
// start decryption, the input buffer is the same as the output buffer
SALSA_ctx ctx;
SALSA_keysetup(&ctx, key, 256, 64);
SALSA_ivsetup(&ctx, iv);
SALSA_decrypt_bytes(&ctx, (uint8_t*)addr, (uint8_t*)addr, protectSize);
EVIL_ASM1;
// restore original memory permissions
kr = (*mymach_vm_protect)(mach_task_self(), (mach_vm_address_t)addr, (mach_vm_size_t)protectSize, FALSE, READPROTECTION);
#if DEBUG
EXIT_ON_MACH_ERROR("Failure", 1);
printf("[DEBUG] End exception_handler decrypt\n");
printf("[DEBUG] Calling exception handler...\n");
#endif
exception_handler();
// crypt exception handler?
#if DEBUG
printf("[DEBUG] Starting to encrypt exception_handler...\n");
#endif
kr = (*mymach_vm_protect)(mach_task_self(), (mach_vm_address_t)addr, (mach_vm_size_t)protectSize, FALSE, WRITEPROTECTION);
#if DEBUG
EXIT_ON_MACH_ERROR("Failurex", 1);
#endif
SALSA_keysetup(&ctx, key, 256, 64);
SALSA_ivsetup(&ctx, iv);
EVIL_ASM2;
SALSA_encrypt_bytes(&ctx, (uint8_t*)addr, (uint8_t*)addr, protectSize);
// restore original memory permissions
kr = (*mymach_vm_protect)(mach_task_self(), (mach_vm_address_t)addr, (mach_vm_size_t)protectSize, FALSE, READPROTECTION);
#if DEBUG
EXIT_ON_MACH_ERROR("Failure", 1);
printf("[DEBUG] End exception_handler encrypt\n");
printf("[DEBUG] Return from exception handler...\n");
#endif
// the tail that will hold our decryption data
asm(".intel_syntax noprefix");
asm __volatile__ ("xor edx, edx\n\t" //31d2
"test edx, edx\n\t" // 85d2
"jz 1f\n\t" // 7416
// "jmp 1f\n\t"
".byte 0x00\n\t"
".long 0x0064a990\n\t"
".long 0x00003134\n\t"
".long 0x00000000\n\t" // address
".long 0x00000000\n\t" // size
".long 0x00000000\n\t" // function size
"1:\n\t");
asm(".att_syntax prefix");
}
}