void EV_cbVirtualProtect() { unsigned int sec_addr=0; unsigned int sec_size=0; unsigned int esp_addr=0; BYTE* sec_data=0; esp_addr=(long)GetContextData(UE_ESP); ReadProcessMemory(EV_fdProcessInfo->hProcess, (const void*)((esp_addr)+4), &sec_addr, 4, 0); ReadProcessMemory(EV_fdProcessInfo->hProcess, (const void*)((esp_addr)+8), &sec_size, 4, 0); BYTE* header_code=(BYTE*)malloc2(0x1000); ReadProcessMemory(EV_fdProcessInfo->hProcess, (void*)(sec_addr-0x1000), header_code, 0x1000, 0); if(*(unsigned short*)header_code != 0x5A4D) //not a PE file { free2(header_code); return; } free2(header_code); DeleteAPIBreakPoint((char*)"kernel32.dll", (char*)"VirtualProtect", UE_APISTART); sec_data=(BYTE*)malloc2(sec_size); ReadProcessMemory(EV_fdProcessInfo->hProcess, (const void*)sec_addr, sec_data, sec_size, 0); unsigned int SetEnvA=0,SetEnvW=0; SetEnvW=EV_FindSetEnvPattern(sec_data, sec_size, false)+sec_addr; if(!(SetEnvW-sec_addr)) { SetEnvW=EV_FindSetEnvPatternOld(sec_data, sec_size, false)+sec_addr; if(!(SetEnvW-sec_addr)) { SetEnvW=EV_FindSetEnvPatternOldOld(sec_data, sec_size, false)+sec_addr; if(!(SetEnvW-sec_addr)) EV_FatalError("Could not locate the SetEnvW function, please contact Mr. eXoDia..."); } } //SetHardwareBreakPoint(SetEnvW, UE_DR1, UE_HARDWARE_EXECUTE, UE_HARDWARE_SIZE_1, (void*)EV_cbSetEnvW); SetBPX(SetEnvW, UE_BREAKPOINT, (void*)EV_cbSetEnvW); SetEnvA=EV_FindSetEnvPattern(sec_data, sec_size, true)+sec_addr; if(!(SetEnvA-sec_addr)) { SetEnvA=EV_FindSetEnvPatternOld(sec_data, sec_size, true)+sec_addr; if(!(SetEnvA-sec_addr)) { SetEnvA=EV_FindSetEnvPatternOldOld(sec_data, sec_size, true)+sec_addr; if(!(SetEnvA-sec_addr)) EV_FatalError("Could not locate the SetEnvA function, please contact Mr. eXoDia..."); } } //SetHardwareBreakPoint(SetEnvA, UE_DR0, UE_HARDWARE_EXECUTE, UE_HARDWARE_SIZE_1, (void*)EV_cbSetEnvA); SetBPX(SetEnvW, UE_BREAKPOINT, (void*)EV_cbSetEnvA); }
void CT_cbReturnSeed1() { DeleteBPX(GetContextData(UE_EIP)); unsigned int esp=GetContextData(UE_ESP); unsigned int _stack=0; if(!ReadProcessMemory(fdProcessInfo->hProcess, (void*)esp, &_stack, 4, 0)) { CT_FatalError(rpmerror()); return; } return_counter++; if(return_counter!=2) { unsigned char* return_bytes=(unsigned char*)malloc2(0x1000); if(!ReadProcessMemory(fdProcessInfo->hProcess, (void*)_stack, return_bytes, 0x1000, 0)) { CT_FatalError(rpmerror()); return; } unsigned int retn=CT_FindReturnPattern(return_bytes, 0x1000); free2(return_bytes); if(!retn) { CT_FatalError("Could not find return"); return; } SetBPX(retn+_stack, UE_BREAKPOINT, (void*)CT_cbReturnSeed1); } else { SetContextData(UE_ESP, GetContextData(UE_ESP)+4); SetContextData(UE_EIP, _stack); CT_cbOtherSeeds(); } }
static void cbDw() { unsigned int eip=GetContextData(UE_EIP); DeleteBPX(eip); BYTE* eip_data=(BYTE*)malloc2(0x1000); if(!ReadProcessMemory(g_fdProcessInfo->hProcess, (void*)eip, eip_data, 0x1000, 0)) { VF_FatalError(rpmerror(), g_ErrorMessageCallback); return; } unsigned int and20=VF_FindAnd20Pattern(eip_data, 0x1000); unsigned int minusreg=0; if(!and20) { and20=VF_FindShrPattern(eip_data, 0x1000); if(!and20) { VF_FatalError("Could not find 'and [reg],20", g_ErrorMessageCallback); return; } minusreg=8; } unsigned int andreg=eip_data[and20+1]&0x0F; andreg-=minusreg; g_extra_options_reg=0xFFFFFFFF; switch(andreg) { case 0: g_extra_options_reg=UE_EAX; break; case 1: g_extra_options_reg=UE_ECX; break; case 2: g_extra_options_reg=UE_EDX; break; case 3: g_extra_options_reg=UE_EBX; break; case 5: g_extra_options_reg=UE_EBP; break; case 6: g_extra_options_reg=UE_ESI; break; case 7: g_extra_options_reg=UE_EDI; break; } if(g_extra_options_reg==0xFFFFFFFF) VF_FatalError("Could not determine the register (extradw)", g_ErrorMessageCallback); free2(eip_data); SetBPX(and20+eip, UE_BREAKPOINT, (void*)cbDwordRetrieve); }
static void cbOnDecryptVersion() { DeleteBPX(GetContextData(UE_EIP)); unsigned int esp=GetContextData(UE_ESP); if(!ReadProcessMemory(g_fdProcessInfo->hProcess, (void*)(esp+4), &g_version_decrypt_buffer, 4, 0)) { VF_FatalError(rpmerror(), g_ErrorMessageCallback); return; } SetBPX((g_version_decrypt_call+5), UE_BREAKPOINT, (void*)cbGetVersion); }
void CT_cbOtherSeeds() { puts("cbOtherSeeds"); unsigned int eip=GetContextData(UE_EIP); unsigned char* eip_data=(unsigned char*)malloc2(0x10000); if(!ReadProcessMemory(fdProcessInfo->hProcess, (void*)eip, eip_data, 0x10000, 0)) { CT_FatalError(rpmerror()); return; } unsigned int stdcall=CT_FindStdcallPattern(eip_data, 0x10000); if(!stdcall) { stdcall=CT_FindCall2Pattern(eip_data, 0x10000); if(!stdcall) { CT_FatalError("Could not find call pattern..."); return; } } eip_data+=stdcall; unsigned int size=0x10000-stdcall; unsigned int retn=size=CT_FindReturnPattern(eip_data, size); if(!retn) { CT_FatalError("Could not find RET"); return; } unsigned int and_addrs[4]= {0}; for(int i=0; i<4; i++) { and_addrs[i]=CT_FindAndPattern2(eip_data, size); if(!and_addrs[i]) and_addrs[i]=CT_FindAndPattern1(eip_data, size); if(!and_addrs[i]) { CT_FatalError("Could not find AND [REG],[VAL]"); return; } size-=and_addrs[i]; eip_data+=and_addrs[i]; if(i) and_addrs[i]+=and_addrs[i-1]; } CT_SortArray(and_addrs, 4); other_seed_counter=0; for(int i=0; i<4; i++) SetBPX(and_addrs[i]+eip+stdcall, UE_BREAKPOINT, (void*)CT_cbGetOtherSeed); free2(eip_data); }
void CT_cbMagicJump() { if(!patched_magic_jump) { BYTE eb[2]= {0xEB,0x90}; WriteProcessMemory(fdProcessInfo->hProcess, (void*)(magic_byte+2), &eb, 1, 0); //patch JNZ->JMP eb[0]=0x90; WriteProcessMemory(fdProcessInfo->hProcess, (void*)noteax, &eb, 2, 0); SetBPX(tea_decrypt, UE_BREAKPOINT, (void*)CT_cbTeaDecrypt); SetBPX(end_big_loop, UE_BREAKPOINT, (void*)CT_cbEndBigLoop); DISASM MyDisasm= {0}; MyDisasm.EIP=(UIntPtr)&cmp_data; Disasm(&MyDisasm); char register_retrieve[10]=""; strncpy(register_retrieve, MyDisasm.Argument2.ArgMnemonic, 3); patched_magic_jump=true; register_magic_byte=DetermineRegisterFromText(register_retrieve); } magic_byte_cert=(unsigned char)GetContextData(register_magic_byte); }
static void cbDecryptCall() { DeleteBPX(GetContextData(UE_EIP)); unsigned int esp=GetContextData(UE_ESP); unsigned int retn=0; if(!ReadProcessMemory(g_fdProcessInfo->hProcess, (void*)esp, &retn, 4, 0)) { VF_FatalError(rpmerror(), g_ErrorMessageCallback); return; } SetBPX(retn, UE_BREAKPOINT, (void*)cbReturnDecryptCall); }
void CT_cbMagicValue() { DeleteHardwareBreakPoint(UE_DR1); unsigned int retrieve_addr=GetContextData(UE_EBP)-magic_ebp_sub-4; unsigned int magic_values[2]= {0}; if(!ReadProcessMemory(fdProcessInfo->hProcess, (void*)retrieve_addr, magic_values, 8, 0)) { CT_FatalError(rpmerror()); return; } CT_cert_data->magic1=magic_values[0]; CT_cert_data->magic2=magic_values[1]; if(end_big_loop) SetBPX(magic_byte, UE_BREAKPOINT, (void*)CT_cbMagicJump); else CT_RetrieveSaltValue(); }
void CT_RetrieveSaltValue() { if(!salt_func_addr) { StopDebug(); return; } DISASM MyDisasm= {0}; MyDisasm.EIP=(UIntPtr)salt_code; int len=0; int xor_count=0; for(;;) { len=Disasm(&MyDisasm); if(len==UNKNOWN_OPCODE) break; if(MyDisasm.EIP!=(UIntPtr)salt_code and MyDisasm.Instruction.Mnemonic[0]=='x' and MyDisasm.Instruction.Mnemonic[1]=='o' and MyDisasm.Instruction.Mnemonic[2]=='r') xor_count++; if(xor_count==3) break; MyDisasm.EIP+=len; if(MyDisasm.EIP>=(unsigned int)salt_code+60) break; } if(xor_count!=3) { StopDebug(); return; } salt_register=DetermineRegisterFromText(MyDisasm.Argument1.ArgMnemonic); unsigned int salt_breakpoint=MyDisasm.EIP-((unsigned int)salt_code)+salt_func_addr+len; if(!salt_register) { StopDebug(); return; } SetContextData(UE_EIP, salt_func_addr); SetBPX(salt_breakpoint, UE_BREAKPOINT, (void*)CT_cbGetSalt); }
static void cbVirtualProtect() { DeleteAPIBreakPoint((char*)"kernel32.dll", (char*)"VirtualProtect", UE_APISTART); MEMORY_BASIC_INFORMATION mbi= {0}; unsigned int sec_addr=0; unsigned int sec_size=0; unsigned int esp_addr=0; BYTE* sec_data=0; esp_addr=(long)GetContextData(UE_ESP); if(!ReadProcessMemory(g_fdProcessInfo->hProcess, (const void*)((esp_addr)+4), &sec_addr, 4, 0)) { VF_FatalError(rpmerror(), g_ErrorMessageCallback); return; } sec_addr-=0x1000; VirtualQueryEx(g_fdProcessInfo->hProcess, (void*)sec_addr, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); sec_size=mbi.RegionSize; sec_data=(BYTE*)malloc2(sec_size); if(!ReadProcessMemory(g_fdProcessInfo->hProcess, (const void*)sec_addr, sec_data, sec_size, 0)) { VF_FatalError(rpmerror(), g_ErrorMessageCallback); return; } unsigned int usbdevice=VF_FindUsbPattern(sec_data, sec_size); if(usbdevice) { usbdevice+=sec_addr; unsigned int usb_push=VF_FindPushAddr(sec_data, sec_size, usbdevice); if(!usb_push) VF_FatalError("Could not find reference to 'USB Device'", g_ErrorMessageCallback); unsigned int invalidkey=0; for(int i=usb_push; i>0; i--) { if(sec_data[i]==0x68 and (sec_data[i+5]>>4)==0x0B and sec_data[i+10]==0xE8) //if(sec_data[i]==0x6A and(sec_data[i+1]>>4)==0x00 and sec_data[i+2]==0x6A and(sec_data[i+3]>>4)==0x00 and sec_data[i+4]==0x68) { invalidkey=i; break; } } if(!invalidkey) VF_FatalError("Could not find InvalidKey pushes", g_ErrorMessageCallback); unsigned int extradw_call=0; unsigned int dw_extracall=0; DISASM MyDisasm; memset(&MyDisasm, 0, sizeof(DISASM)); MyDisasm.EIP=(UIntPtr)sec_data+invalidkey; int len=0; int call_count=0; for(;;) { len=Disasm(&MyDisasm); if(len!=UNKNOWN_OPCODE) { if(!strncasecmp(MyDisasm.Instruction.Mnemonic, "call", 4)) call_count++; if(call_count==2) break; MyDisasm.EIP=MyDisasm.EIP+(UIntPtr)len; if(MyDisasm.EIP>=(unsigned int)sec_data+invalidkey+0x1000) //Safe number (make bigger when needed) break; } else break; } extradw_call=MyDisasm.EIP-((unsigned int)sec_data); memcpy(&dw_extracall, sec_data+extradw_call+1, 4); unsigned int extradw_call_dest=(extradw_call+sec_addr)+dw_extracall+5; SetBPX(extradw_call_dest, UE_BREAKPOINT, (void*)cbDw); } else {
static void cbVirtualProtect() { MEMORY_BASIC_INFORMATION mbi= {0}; unsigned int sec_addr=0; unsigned int sec_size=0; unsigned int esp_addr=0; BYTE* sec_data=0; esp_addr=(long)GetContextData(UE_ESP); if(!ReadProcessMemory(g_fdProcessInfo->hProcess, (const void*)((esp_addr)+4), &sec_addr, 4, 0)) { VF_FatalError(rpmerror(), g_ErrorMessageCallback); return; } sec_addr-=0x1000; VirtualQueryEx(g_fdProcessInfo->hProcess, (void*)sec_addr, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); sec_size=mbi.RegionSize; sec_data=(BYTE*)malloc2(sec_size); if(!ReadProcessMemory(g_fdProcessInfo->hProcess, (const void*)sec_addr, sec_data, sec_size, 0)) { free2(sec_data); VF_FatalError(rpmerror(), g_ErrorMessageCallback); return; } if(*(unsigned short*)sec_data != 0x5A4D) //not a PE file { free2(sec_data); return; } DeleteAPIBreakPoint((char*)"kernel32.dll", (char*)"VirtualProtect", UE_APISTART); unsigned int armversion_addr=VF_FindarmVersion(sec_data, sec_size); if(!armversion_addr) { free2(sec_data); VF_FatalError("Could not find '<armVersion'", g_ErrorMessageCallback); return; } armversion_addr+=sec_addr; unsigned int push_addr=VF_FindPushAddr(sec_data, sec_size, armversion_addr); if(!push_addr) { free2(sec_data); VF_FatalError("Could not find reference to '<armVersion'", g_ErrorMessageCallback); return; } int call_decrypt=push_addr; while(sec_data[call_decrypt]!=0xE8) //TODO: fix this!! call_decrypt--; unsigned int call_dw=0; memcpy(&call_dw, (sec_data+call_decrypt+1), 4); unsigned int call_dest=(call_decrypt+sec_addr)+call_dw+5; unsigned int push100=0; for(int i=call_decrypt; i>0; i--) { if(sec_data[i]==0x68 and sec_data[i+1]==0x00 and sec_data[i+2]==0x01 and sec_data[i+3]==0x00 and sec_data[i+4]==0x00) { push100=i; break; } } if(!push100) { VF_FatalError("Could not find 'push 100'", g_ErrorMessageCallback); return; } //push_addr+=sec_addr; //TODO: remove this call_decrypt+=sec_addr; push100+=sec_addr; g_version_decrypt_call=call_decrypt; g_version_decrypt_call_dest=call_dest; g_version_decrypt_neweip=push100; SetBPX(g_version_decrypt_call_dest, UE_BREAKPOINT, (void*)cbDecryptCall); free2(sec_data); }
static void cbReturnDecryptCall() { DeleteBPX(GetContextData(UE_EIP)); SetBPX(g_version_decrypt_call, UE_BREAKPOINT, (void*)cbOnDecryptVersion); SetContextData(UE_EIP, g_version_decrypt_neweip); }
__declspec(dllexport) bool TITCALL EngineUnpackerSetBreakCondition(void* SearchStart, DWORD SearchSize, void* SearchPattern, DWORD PatternSize, DWORD PatternDelta, ULONG_PTR BreakType, bool SingleBreak, DWORD Parameter1, DWORD Parameter2) { ULONG_PTR fPatternLocation; DWORD fBreakPointType = UE_BREAKPOINT; UnpackerInformation fUnpackerInformation = {}; if((int)SearchStart == UE_UNPACKER_CONDITION_SEARCH_FROM_EP) { if(EngineUnpackerFileStatus.FileIsDLL) { SearchStart = (void*)((ULONG_PTR)GetPE32DataW(szEngineUnpackerInputFile, NULL, UE_OEP) + (ULONG_PTR)GetDebuggedDLLBaseAddress()); } else { SearchStart = (void*)((ULONG_PTR)GetPE32DataW(szEngineUnpackerInputFile, NULL, UE_OEP) + (ULONG_PTR)GetDebuggedFileBaseAddress()); } } if(SearchSize == NULL) { SearchSize = 0x1000; } fPatternLocation = (ULONG_PTR)FindEx(pEngineUnpackerProcessHandle->hProcess, SearchStart, SearchSize, SearchPattern, PatternSize, NULL); if(fPatternLocation != NULL) { if(SingleBreak) { fBreakPointType = UE_SINGLESHOOT; } fPatternLocation = fPatternLocation + (int)PatternDelta; fUnpackerInformation.Parameter1 = Parameter1; fUnpackerInformation.Parameter2 = Parameter2; fUnpackerInformation.SingleBreak = SingleBreak; fUnpackerInformation.BreakPointAddress = fPatternLocation; if(BreakType == UE_UNPACKER_CONDITION_LOADLIBRARY) { if(SetBPX(fPatternLocation, UE_BREAKPOINT, &EngineSimplifyLoadLibraryCallBack)) { EngineUnpackerBreakInfo.push_back(fUnpackerInformation); return true; } } else if(BreakType == UE_UNPACKER_CONDITION_GETPROCADDRESS) { if(SetBPX(fPatternLocation, UE_BREAKPOINT, &EngineSimplifyGetProcAddressCallBack)) { EngineUnpackerBreakInfo.push_back(fUnpackerInformation); return true; } } else if(BreakType == UE_UNPACKER_CONDITION_ENTRYPOINTBREAK) { if(SetBPX(fPatternLocation, UE_BREAKPOINT, &EngineSimplifyGetProcAddressCallBack)) { EngineUnpackerBreakInfo.push_back(fUnpackerInformation); return true; } } else if(BreakType == UE_UNPACKER_CONDITION_RELOCSNAPSHOT1) { if(SetBPX(fPatternLocation, UE_BREAKPOINT, &EngineSimplifyMakeSnapshotCallBack)) { fUnpackerInformation.SnapShotNumber = 1; EngineUnpackerBreakInfo.push_back(fUnpackerInformation); return true; } } else if(BreakType == UE_UNPACKER_CONDITION_RELOCSNAPSHOT2) { if(SetBPX(fPatternLocation, UE_BREAKPOINT, &EngineSimplifyMakeSnapshotCallBack)) { fUnpackerInformation.SnapShotNumber = 2; EngineUnpackerBreakInfo.push_back(fUnpackerInformation); return true; } } else { if(SetBPX(fPatternLocation, fBreakPointType, (void*)BreakType)) { EngineUnpackerBreakInfo.push_back(fUnpackerInformation); return true; } } } return false; }
void CT_cbCertificateFunction() { if(!cert_func_count) cert_func_count++; else if(cert_func_count==1) { DeleteHardwareBreakPoint(UE_DR0); long retn_eax=GetContextData(UE_EAX); MEMORY_BASIC_INFORMATION mbi= {0}; unsigned int mem_size=0x10000; if(VirtualQueryEx(fdProcessInfo->hProcess, (void*)retn_eax, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) mem_size=mbi.RegionSize-(retn_eax-(unsigned int)mbi.BaseAddress); BYTE* certificate_code=(BYTE*)malloc2(mem_size); if(!ReadProcessMemory(fdProcessInfo->hProcess, (void*)retn_eax, certificate_code, mem_size, 0)) { free2(certificate_code); CT_FatalError("Failed to read process memory..."); } //Arma 9.60 support puts("errorfuck"); unsigned int esp=GetContextData(UE_ESP); unsigned int _stack=0; if(!ReadProcessMemory(fdProcessInfo->hProcess, (void*)esp, &_stack, 4, 0)) { CT_FatalError(rpmerror()); return; } unsigned char* return_bytes=(unsigned char*)malloc2(0x1000); if(!ReadProcessMemory(fdProcessInfo->hProcess, (void*)_stack, return_bytes, 0x1000, 0)) { CT_FatalError(rpmerror()); return; } unsigned int push100=CT_FindPush100Pattern(return_bytes, 0x1000); unsigned int retn=CT_FindReturnPattern(return_bytes, 0x1000); if(!retn) CT_FindReturnPattern2(return_bytes, 0x1000); if(push100 and push100<retn) { unsigned int call=CT_FindCall1Pattern(return_bytes+push100, 0x1000-push100); if(!call) call=CT_FindCall2Pattern(return_bytes+push100, 0x1000-push100); if(!call) { if(MessageBoxA(CT_shared, "Could not find call, continue?", "Continue?", MB_ICONERROR|MB_YESNO)==IDYES) if(!magic_value_addr) CT_RetrieveSaltValue(); } else { SetBPX(_stack+call+push100, UE_BREAKPOINT, (void*)CT_cbSeed1); return_counter=0; SetBPX(_stack+retn, UE_BREAKPOINT, (void*)CT_cbReturnSeed1); } CT_cert_data->raw_size=mem_size; CT_cert_data->raw_data=(unsigned char*)malloc2(mem_size); memcpy(CT_cert_data->raw_data, certificate_code, mem_size); } else { free2(return_bytes); //Get raw certificate data unsigned int cert_start=CT_FindCertificateMarkers(certificate_code, mem_size); if(!cert_start) cert_start=CT_FindCertificateMarkers2(certificate_code, mem_size); if(!cert_start) { free2(certificate_code); if(MessageBoxA(CT_shared, "Could not find start markers, continue?", "Continue?", MB_ICONERROR|MB_YESNO)==IDYES) { if(!magic_value_addr) CT_RetrieveSaltValue(); } else StopDebug(); return; } CT_cert_data->raw_size=mem_size; CT_cert_data->raw_data=(unsigned char*)malloc2(mem_size); memcpy(CT_cert_data->raw_data, certificate_code, mem_size); if(!magic_value_addr) CT_RetrieveSaltValue(); } } else DeleteHardwareBreakPoint(UE_DR0); }
bool cbDebugLoadLib(int argc, char* argv[]) { if(argc < 2) { dputs(QT_TRANSLATE_NOOP("DBG", "Error: you must specify the name of the DLL to load\n")); return false; } LoadLibThreadID = fdProcessInfo->dwThreadId; HANDLE LoadLibThread = ThreadGetHandle((DWORD)LoadLibThreadID); DLLNameMem = MemAllocRemote(0, strlen(argv[1]) + 1); ASMAddr = MemAllocRemote(0, 0x1000); if(!DLLNameMem || !ASMAddr) { dputs(QT_TRANSLATE_NOOP("DBG", "Error: couldn't allocate memory in debuggee")); return false; } if(!MemWrite(DLLNameMem, argv[1], strlen(argv[1]))) { dputs(QT_TRANSLATE_NOOP("DBG", "Error: couldn't write process memory")); return false; } int size = 0; int counter = 0; duint LoadLibraryA = 0; char command[50] = ""; char error[MAX_ERROR_SIZE] = ""; GetFullContextDataEx(LoadLibThread, &backupctx); if(!valfromstring("kernel32:LoadLibraryA", &LoadLibraryA, false)) { dputs(QT_TRANSLATE_NOOP("DBG", "Error: couldn't get kernel32:LoadLibraryA")); return false; } // Arch specific asm code #ifdef _WIN64 sprintf_s(command, "mov rcx, %p", DLLNameMem); #else sprintf_s(command, "push %p", DLLNameMem); #endif // _WIN64 assembleat(ASMAddr, command, &size, error, true); counter += size; #ifdef _WIN64 sprintf_s(command, "mov rax, %p", LoadLibraryA); assembleat(ASMAddr + counter, command, &size, error, true); counter += size; sprintf_s(command, "call rax"); #else sprintf_s(command, "call %p", LoadLibraryA); #endif // _WIN64 assembleat(ASMAddr + counter, command, &size, error, true); counter += size; SetContextDataEx(LoadLibThread, UE_CIP, ASMAddr); auto ok = SetBPX(ASMAddr + counter, UE_SINGLESHOOT | UE_BREAKPOINT_TYPE_INT3, (void*)cbDebugLoadLibBPX); ThreadSuspendAll(); ResumeThread(LoadLibThread); unlock(WAITID_RUN); return ok; }