Reputation: 63
In my app I'm getting battery infos using this way (via IOKit).
static void print_raw_battery_state(io_registry_entry_t b_reg) {
CFBooleanRef boo;
CFNumberRef n;
int tmp;
int cur_cap = -1;
int max_cap = -1;
CFMutableDictionaryRef prop = NULL;
IOReturn ret;
ret = IORegistryEntryCreateCFProperties(b_reg, &prop, 0, 0);
if( (kIOReturnSuccess != ret) || (NULL == prop) )
{
printf("Couldn't read battery status; error = 0%08x\n", ret);
return;
}
boo = CFDictionaryGetValue(prop, CFSTR(kIOPMPSExternalConnectedKey));
printf(" external connected = %s\n",
(kCFBooleanTrue == boo) ? "yes" : "no");
boo = CFDictionaryGetValue(prop, CFSTR(kIOPMPSBatteryInstalledKey));
printf(" battery present = %s\n",
(kCFBooleanTrue == boo) ? "yes" : "no");
boo = CFDictionaryGetValue(prop, CFSTR(kIOPMPSIsChargingKey));
printf(" battery charging = %s\n",
(kCFBooleanTrue == boo) ? "yes" : "no");
n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSCurrentCapacityKey));
if(n) {
CFNumberGetValue(n, kCFNumberIntType, &cur_cap);
}
n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSCurrentCapacityKey));
if(n) {
CFNumberGetValue(n, kCFNumberIntType, &max_cap);
}
if( (-1 != cur_cap) && (-1 != max_cap) )
{
printf(" cap = %d/%d\n", cur_cap, max_cap);
gcurCapacity = cur_cap;//hab
gmaxCapacity = max_cap;//hab
}
n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSTimeRemainingKey));
if(n) {
CFNumberGetValue(n, kCFNumberIntType, &tmp);
NSLog(@" time REM = %d:%02d\n", tmp/60, tmp%60);
printf("time cicA = %d:%02d\n", tmp/60, tmp%60);
NSString *stringTimeRem = [NSString stringWithFormat:@"%d:%02d", tmp/60, tmp%60];
[[NSUserDefaults standardUserDefaults] setObject:stringTimeRem forKey:@"stringREM"];
}
n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSAmperageKey));
if(n) {
CFNumberGetValue(n, kCFNumberIntType, &tmp);
gcurrent = tmp;//hab
printf(" current = %d\n", tmp);
}
n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSCycleCountKey));
if(n) {
CFNumberGetValue(n, kCFNumberIntType, &tmp);
printf(" cycle count = %d\n", tmp);
gloadcycles = tmp;//hab
}
n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSLocationKey));
if(n) {
CFNumberGetValue(n, kCFNumberIntType, &tmp);
printf(" location = %d\n", tmp);
}
printf("\n");
CFRelease(prop);
return;}
How can I access those infos using dlopen ? I need to get IOReturn and io_registry_entry_t using dlopen, so Apple won't probably find that IOKit is there. Thanks.
Upvotes: 1
Views: 1202
Reputation: 559
#import "ViewController.h"
#import "IOKit/IOKitLib.h"
#import "IOKit/IOPSKeys.h"
#include <dlfcn.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
static mach_port_t *s_kIOMasterPortDefault;
static kern_return_t (*s_IORegistryEntryCreateCFProperties)(mach_port_t entry, CFMutableDictionaryRef *properties, CFAllocatorRef allocator, UInt32 options);
static mach_port_t (*s_IOServiceGetMatchingService)(mach_port_t masterPort, CFDictionaryRef matching CF_RELEASES_ARGUMENT);
static CFMutableDictionaryRef (*s_IOServiceMatching)(const char *name);
static CFMutableDictionaryRef g_powerSourceService;
static mach_port_t g_platformExpertDevice;
static BOOL foundSymbols = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
void* handle = dlopen("/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit", RTLD_LAZY);
s_IORegistryEntryCreateCFProperties = dlsym(handle, "IORegistryEntryCreateCFProperties");
s_kIOMasterPortDefault = dlsym(handle, "kIOMasterPortDefault");
s_IOServiceMatching = dlsym(handle, "IOServiceMatching");
s_IOServiceGetMatchingService = dlsym(handle, "IOServiceGetMatchingService");
if (s_IORegistryEntryCreateCFProperties && s_IOServiceMatching && s_IOServiceGetMatchingService) {
g_powerSourceService = s_IOServiceMatching("IOPMPowerSource");
g_platformExpertDevice = s_IOServiceGetMatchingService(*s_kIOMasterPortDefault, g_powerSourceService);
foundSymbols = (g_powerSourceService && g_platformExpertDevice);
}
});
if (!foundSymbols) {
return;
}
print_raw_battery_state(g_platformExpertDevice);
}
static void print_raw_battery_state(io_registry_entry_t b_reg) {
CFBooleanRef boo;
CFNumberRef n;
int tmp;
int cur_cap = -1;
int max_cap = -1;
CFMutableDictionaryRef prop = NULL;
IOReturn ret;
ret = IORegistryEntryCreateCFProperties(b_reg, &prop, 0, 0);
if( (kIOReturnSuccess != ret) || (NULL == prop) )
{
printf("Couldn't read battery status; error = 0%08x\n", ret);
return;
}
// battery dictionary
NSLog(@"prop: %@", prop);
printf("\n");
CFRelease(prop);
return;
}
}
@end
In iOS 11 and 12, you will only get a few values.
Upvotes: 0
Reputation: 4055
H2CO3 is correct. Just #include
ing IOKit doesn't affect the compiled code at all. It's when you directly use the functions defined in the IOKit headers and link against IOKit that the private framework can clearly be seen in your app. One form of obfuscation for hiding the private framework and symbols used is a simple cipher shift. For example, using H2CO3's example:
// Deciphers string in-place and returns a pointer to it
__attribute__((always_inline)) char* decipher(char* str) {
int i, n = strlen(str);
for(i = 0; i < n; i++) str[i]--;
return str;
}
//...
char sym[] = "JPSfhjtuszFouszDsfbufDGQspqfsujft";
char fr[] = "Gsbnfxpslt";
char fmwk[] = "JPLju";
char lib[60];
decipher(fmwk);
sprintf(lib, "/System/Library/%s/%s.framework/Versions/A/%s", fr, fmwk, fmwk);
void* handle = dlopen(lib, RTLD_LAZY);
IOReturn (*fptr)(io_registry_event_t, CFMutableDictionaryRef*,i int, int);
fptr = dlsym(handle, decipher(sym));
// Now just call fptr() as if it were IORegistryEntryCreateCFProperties()
The difference between this and H2CO3's version is that this will prevent people manually analyzing the app from finding IOKit at all without a reasonable amount of expertise. Of course, a determined reverser can still find the usage of IOKit no matter how well you try to hide it. Obfuscation is useful here because App Store reviewers likely won't devote their time to reversing your app for days. Also, remember to strip
your app before you submit it. I think stripping is enabled by default in Xcode, but I'm not sure. You'll need to figure that one out yourself.
Upvotes: 0
Reputation:
I need to get
IOReturn
andio_registry_entry_t
using dlopen
Those are just types. They're declared in header files, and not compiled into the IOKit library. You can't get those using dlopen()
.
so Apple won't probably find that IOKit is there
Again, types aren't explicitly represented in the binary. If Apple finds out that you're using IOKit, then the reason for that will not be the use of these types. They're the function names that betray.
However, if you use dlopen()
to retrieve a pointer to these functions, the strings representing function names will still be an open book to Apple's static analysis tools. You may have to do some additional obfuscation in order the binary not to expose directly the private function names:
NSString *secondPart = @"ateCFProperties";
NSString *firstPart = @"IORegistryEntryCre";
const char *fname = [[firstPart stringByAppendingString:secondPart] UTF8String];
IOReturn (*fptr)(io_registry_entry_t, CFMutableDictionaryRef *, int, int);
fptr = dlsym(dyld_handle, fname);
etc.
Upvotes: 2