IOKit使用dlopen

时间:2013-04-27 16:18:49

标签: iphone objective-c battery dlopen iokit

在我的应用程序中,我正在使用这种方式获取电池信息(通过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;}

如何使用dlopen访问这些信息?我需要使用dlopen来获取IOReturn和io_registry_entry_t,因此Apple可能不会发现IOKit存在。 感谢。

3 个答案:

答案 0 :(得分:2)

  

我需要使用dlopen

获取IOReturnio_registry_entry_t

那些只是类型。它们在头文件中声明,编译到IOKit库中。你不能使用dlopen()获得那些。

  

所以Apple可能不会发现IOKit在那里

同样,类型未在二进制文件中明确表示。如果Apple发现您正在使用IOKit,那么的原因将不会使用这些类型。它们是背叛的功能名称。

但是,如果使用dlopen()检索指向这些函数的指针,则表示函数名称的字符串仍然是Apple静态分析工具的开放式书籍。您可能必须进行一些额外的混淆,以使二进制文件不直接公开私有函数名称:

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);

答案 1 :(得分:0)

H2CO3是正确的。只是#include IOKit根本不会影响编译代码。当您直接使用IOKit头中定义的函数并链接到IOKit时,可以在您的应用中清楚地看到私有框架。隐藏所使用的私有框架和符号的一种混淆形式是简单的密码转换。例如,使用H2CO3的例子:

// 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()

这与H2CO3的版本之间的区别在于,这将阻止人们手动分析应用程序,在没有合理数量的专业知识的情况下完全找到IOKit。当然,无论你试图隐藏它的程度如何,确定的反向器仍然可以找到IOKit的用法。混淆在这里很有用,因为App Store评论员可能不会花费时间将您的应用程序反转几天。另外,在提交之前,请记住strip您的应用。我认为在Xcode中默认启用剥离,但我不确定。你需要自己解决这个问题。

答案 2 :(得分:0)

#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

在iOS 11和12中,您只会得到一些值。