You may have heard of Hex-Rays IDA Pro. You may even have used their demo version, to run into the 32-bit only code restriction. Not only that, the full version is also way too expensive for us hobby developers.
The good news is that we don’t have to use IDA Pro. I myself use the Hopper Disassembler. This is a very nice and affordable tool. Even the demo version supports 64-bit code, and the full version is only $59.99 so that is pie-nuts compared to IDA Pro. And here is an example of why I like it so much:
function X86PlatformShim::start(IOService*) { r15 = rsi; rbx = rdi; var_4 = 0x0; *(rbx + 0x88) = 0x0; *(rbx + 0xd0) = 0x0; rax = (*(*0x5058 + 0x5d0))(); r14 = rax; rax = loc_b8c(); *(rbx + 0x90) = rax; if (rax == 0x0) goto loc_ec0; goto loc_b98; loc_ec0: r14 = 0x0; loc_ed3(0x0, 0x3, 0x0); loc_ed3: rax = r14; return rax; loc_b98: rax = loc_ba2(rbx, 0x0); *(rbx + 0x98) = rax; if (rax == 0x0) goto loc_bda; goto loc_bae; loc_bda: loc_be1: loc_bf1(0x0, 0x3, 0x0); loc_bf1: rax = loc_bfd("CPU_Power_Limits"); *_gIOPMCPUPowerLimitsKey = rax; rax = loc_c10("CPU_Speed_Limit"); *_gIOPMCPUPowerLimitProcessorSpeedKey = rax; rax = loc_c23("CPU_Available_CPUs"); *_gIOPMCPUPowerLimitProcessorCountKey = rax; rax = loc_c36("CPU_Scheduler_Limit"); *_gIOPMCPUPowerLimitSchedulerTimeKey = rax; rax = loc_c49("cpu-plimit-notification"); *(rbx + 0x108) = rax; if (rax == 0x0) goto loc_ec0; rax = loc_c65("cpu-idle-plimit-notification"); *(rbx + 0x110) = rax; if (rax == 0x0) goto loc_ec0; rax = loc_c81("CPUCStates"); *(rbx + 0xa0) = rax; if (rax == 0x0) goto loc_ec0; rax = loc_c9d("CPUOnACPower"); *(rbx + 0xa8) = rax; if (rax == 0x0) goto loc_ec0; rax = loc_cbf(r15, **0x5018); *(rbx + 0x150) = rax; if (rax == 0x0) goto loc_ec0; rax = loc_cdd("IOPMrootDomain", 0x0); if (rax == 0x0) goto loc_eef; goto loc_ce9; loc_eef: r14 = 0x0; loc_f02(0x0, 0x3, 0x0); goto loc_ed3; loc_ce9: rax = loc_cf8(r15, 0xffffffff); rax = loc_d0a(rax, **0x5010); *(rbx + 0xc8) = rax; (*(*r15 + 0x28))(r15); if (*(rbx + 0xc8) == 0x0) goto loc_eb9; goto loc_d28; loc_eb9: goto loc_ec0; loc_d28: rax = loc_d36(0xc0045800, &var_4); if ((rax == 0x0) && (var_4 == 0x2)) goto loc_d48; goto loc_e07; loc_d48: *(int32_t *)(rbx + 0xc4) = 0x1; rax = loc_d5e("XCPM"); *(rbx + 0x88) = rax; *(rbx + 0x128) = X86PlatformShim::setPStateEntryInfoXCPM(int, int, int); *(rbx + 0x130) = X86PlatformShim::sendPStateTableInfoXCPM(int); *(rbx + 0x138) = X86PlatformShim::sendPLimitXCPM(int); *(rbx + 0x140) = X86PlatformShim::sendIdlePLimitXCPM(int, int); *(rbx + 0x148) = X86PlatformShim::sendPStateStepperTableXCPM(IOService*); X86PlatformShim::initializePMInfo(rbx); goto loc_ed3; loc_e07: *(int32_t *)(rbx + 0xc4) = 0x0; *(rbx + 0x128) = X86PlatformShim::setPStateEntryInfoAICPM(int, int, int); *(rbx + 0x130) = X86PlatformShim::sendPStateTableInfoAICPM(int); *(rbx + 0x138) = X86PlatformShim::sendPLimitAICPM(int); *(rbx + 0x140) = X86PlatformShim::sendIdlePLimitAICPM(int, int); *(rbx + 0x148) = X86PlatformShim::sendPStateStepperTableAICPM(IOService*); rax = loc_e65("AppleIntelCPUPowerManagement", 0x0); if (rax == 0x0) goto loc_ee1; goto loc_e6d; loc_ee1: goto loc_eef; loc_e6d: rax = loc_e8f(**0x5068, r15, X86PlatformShim::aicpmNotification(void*, IOService*, IONotifier*), rbx, 0x0, 0x0); *(rbx + 0xd0) = rax; (*(*r15 + 0x28))(r15); if (*(rbx + 0xd0) != 0x0) goto loc_ed3; goto loc_eef; loc_bae: rax = (*(**(rbx + 0x90) + 0x140))(*(rbx + 0x90), rax); if (rax == 0x0) goto loc_bf1; goto loc_be1; }
This sort of pseudo code makes finding the stuff that we are interested in easy to locate. Let’s take a look at one particular line in the above code snippet:
if ((rax == 0x0) && (var_4 == 0x2)) goto loc_d48;
This selects the desired power management features. In our case we use XCPM but older (like Sandy Bridge) processors will fall back to using the AppleIntelCPUPowerManagement (kext).
Anyway. Next time you are looking for a disassembler… give Hopper Disassembler a go 😉