1

在我的应用程序中,我使用这种方式(通过 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 存在。谢谢。

4

3 回答 3

2

我需要获取IOReturnio_registry_entry_t使用 dlopen

这些只是类型。它们在头文件中声明,而不是编译到 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);

等等

于 2013-04-27T16:27:03.033 回答
0

H2CO3 是正确的。只是#includeIOKit 根本不会影响已编译的代码。当您直接使用 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 中默认启用剥离,但我不确定。你需要自己弄清楚这一点。

于 2013-04-29T23:48:47.700 回答
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 中,您只会得到几个值。

于 2018-10-04T16:42:28.703 回答