热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Hooking&ExecutingCodewithdlopen&dlsymCfunctions

Easymode:hookingCfunctionsSettingupyourprojectThisprojectisverysimple.Allitdoesisdisplayaw

Easy mode: hooking C functions

Setting up your project

This project is very simple. All it does is display a watermarked image in a UIImageView.

Easy mode: hooking C functions

you’ll be going after the getenv C function. This simple C function takes a char * (null terminated string) for input and returns the environment variable for the parameter you supply.

Open and launch the Watermark project in Xcode. Create a new symbolic breakpoint, putting getenv in the Symbol section. Next, add a custom action with the following:

po (char *)$rdi

Now, make sure the execution automatically continues after the breakpoint hits.

Finally, build and run the application on the iPhone Simulator then watch the console. You’ll get a slew of output indicating this method is called quite frequently. It’ll look similar to the following:

"DYLD_INSERT_LIBRARIES"
"NSZombiesEnabled"
"OBJC_DEBUG_POOL_ALLOCATION"
"MallocStackLogging"
"MallocStackLoggingNoCompact"
"OBJC_DEBUG_MISSING_POOLS"
"LIBDISPATCH_DEBUG_QUEUE_INVERSIONS"
"LIBDISPATCH_CONTINUATION_ALLOCATOR"
"XPC_FLAGS"
"XPC_NULL_BOOTSTRAP"
"XBS_IS_CHROOTED"
"XPC_SERVICES_UNAVAILABLE"
"XPC_SIMULATOR_LAUNCHD_NAME"
"CLASSIC"
"LANG"
"XPC_SIMULATOR_LAUNCHD_NAME"

you want to have the function hooked before your application starts up, you’ll need to create a dynamic framework to put the hooking logic in so it’ll be available before the main function is called. You’ll explore this easy case of hooking a C function inside your own executable first.

Open AppDelegate.swift, and replace
application(_:didFinishLaunchingWithOptions:) with the following:

func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
if let cString = getenv("HOME") {
let homeEnv = String(cString: cString)
print("HOME env: \(homeEnv)")
}
return true
}

This creates a call to getenv to get the HOME environment variable.
Next, remove the symbolic getenv breakpoint you previously created and build and
run the application.
The console output will look similar to the following:

"HOME"
HOME env: /Users/devzkn/Library/Developer/CoreSimulator/Devices/2499648A-9622-42D9-8931-C342DB0208CC/data/Containers/Data/Application/81D1A334-A8C2-498E-87E9-950626126918

In Xcode, navigate to FileNewTarget and select Cocoa Touch Framework. Choose HookingC as the product name, and set the language to Objective-C.

Once this new framework is created, create a new C file. In Xcode, select FileNewFile, then select C file. Name this file getenvhook. Uncheck the checkbox for Also create a header file. Save the file with the rest of the project.

Make sure this file belongs to the HookingC framework that you’ve just created, and not Watermark.

Open getenvhook.c and replace its contents with the following:

import import import import import

/**
• dlfcn.h will be responsible for two very interesting functions: dlopen and dlsym.
• assert.h the assert will test the library containing the real getenv is correctly loaded.
• stdio.h will be used temporarily for a C printf call.
• dispatch.h will be used to to properly set up the logic for GCD’s dispatch_once
function.
• string.h will be used for the strcmp function, which compares two C strings.
*/

Next, redeclare the getenv function with the hard-coded stub shown below:

char * getenv(const char *name) {
return "YAY!";
}

Finally, build and run your application to see what happens. You’ll get the following output:
HOME env: YAY!

HOME env: YAY!
"IPHONE_SIMULATOR_ROOT"
IPHONE_SIMULATOR_ROOT: YAY!

Awesome! You were able to successfully replace this method with your own function.

However, this isn’t quite what you want. You want to call the original getenv function and augment the return value if “HOME” is supplied as input.

What would happen if you tried to call the original getenv function inside your getenv function? Try it out and see what happens. Add some temporary code so the getenv looks like the following:

char * getenv(const char *name) {
return getenv(name);
return "YAY!";
}

如果要在Terminal进行lldb的话,就关闭Xcode的运行,使用模拟器单独启动Watermark

如果要在Xcode进行lldb 的话,可以设置个断点即可

devzkndeMacBook-Pro:~ devzkn$ lldb -n Watermark

image lookup -s getenv
1 symbols match 'getenv' in /Users/devzkn/Library/Developer/Xcode/DerivedData/Watermark-eqvbswmyqiyhvgbqmiqzpnnzylsn/Build/Products/Debug-iphonesimulator/Watermark.app/Frameworks/HookingC.framework/HookingC:
Address: HookingC[0x0000000000000f60] (HookingC.__TEXT.__text + 0)
Summary: HookingC`getenv at getenvhook.c:29
1 symbols match 'getenv' in /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk//usr/lib/system/libsystem_c.dylib:
Address: libsystem_c.dylib[0x000000000005ca26] (libsystem_c.dylib.__TEXT.__text + 375174)
Summary: libsystem_c.dylib`getenv

You’ll get two hits. One of them will be the getenv function you created yourself. More importantly, you’ll get the location of the getenv function you actually care about. It looks like this function is located in libsystem_c.dylib, and its full path is at /usr/lib/system/libsystem_c.dylib. Remember, the simulator prepends that big long path to these directories, but the dynamic linker is smart enough to search in the correct areas. Everything after iPhoneSimulator.sdk is where this framework is actually stored on a real iOS device.

Now you know exactly where this function is loaded, it’s time to whip out the first of the amazing “dl” duo, dlopen. Its function signature looks like the following:

extern void * dlopen(const char * __path, int __mode);
extern void * dlsym(void * __handle, const char * __symbol);```
dlopen expects a fullpath in the form of a char * and a second parameter, which is a mode expressed as an integer that determines how dlopen should load the module. If successful, dlopen returns an opaque handle (a void *) ,or NULL if it fails.
After dlopen (hopefully) returns a reference to the module, you’ll use dlsym to get a reference to the getenv function. dlsym has the following function signature:
extern void * dlsym(void * __handle, const char * __symbol);
dlsym expects to take the reference generated by dlopen as the first parameter and the name of the function as the second parameter. If everything goes well, dlsym will return the function address for the symbol specified in the second parameter or NULL if it failed.
Replace your getenv function with the following:

char getenv(const char name) {
void *handle = dlopen(“/usr/lib/system/libsystem_c.dylib”, RTLD_NOW);
assert(handle);
void *real_getenv = dlsym(handle, “getenv”);
printf(“Real getenv: %pnFake getenv: %pn”, real_getenv, getenv);
return “YAY!”;
}

You used the RTLD_NOW mode of dlopen to say, “Hey, don’t wait or do any cute lazy loading stuff. Open this module right now.” After making sure the handle is not NULL through a C assert, you call dlsym to get a handle on the “real” getenv.
Build and run the application. You’ll get output similar to the following:

Real getenv: 0x10fde4a26
Fake getenv: 0x10d081df0


Right now, the real_getenv function pointer is void *, meaning it could be anything. You already know the function signature of getenv, so you can simply cast it to that.
Replace your getenv function one last time with the following:

char * getenv(const char *name) {
static void *handle; // 1
static char * (*real_getenv)(const char *); // 2
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ // 3
handle = dlopen("/usr/lib/system/libsystem_c.dylib", RTLD_NOW);
assert(handle);
real_getenv = dlsym(handle, "getenv");
});
if (strcmp(name, "HOME") == 0) { // 4
return "/"; }
return real_getenv(name); // 5
}

You might not be used to this amount of C code, so let’s break it down:

  1. Thiscreatesastaticvariablenamedhandle.It’sstaticsothisvariablewill survive the scope of the function. That is, this variable will not be erased when the function exits, but you’ll only be able to access it inside the getenv function.
  2. You’re doing the same thing here as you declare the real_getenv variableas static, but you’ve made other changes to the real_getenv function pointer. You’ve cast this function pointer to correctly match the signature of getenv. This will allow you to call the real getenv function through the real_getenv variable. Cool, right?
  3. You’re using GCD’s dispatch_once because you really only need to call the setup once. This nicely complements the static variables you declared a couple lines

    1. You don’t want to be doing the lookup logic every time your augmented
  4. runs!
  5. You’re using C’s strcmp to see ifyou’re querying the “HOME” environment variable. If it’s true, you’re simply returning “/” to signify the root directory. Essentially, you’re overriding what the getenv function returns.
  6. If “HOME” is not supplied as an input parameter,then just fallback on the default getenv.

Find application(_:didFinishLaunchingWithOptions:) in AppDelegate.swift. Replace this method with:

func application(_ application: UIApplication,

didFinishLaunchingWithOptions launchOptions:
[UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
if let cString = getenv("HOME") {
let homeEnv = String(cString: cString)
print("HOME env: \(homeEnv)")
} if let cString = getenv("IPHONE_SIMULATOR_ROOT") {
let homeEnv = String(cString: cString)
print(" IPHONE_SIMULATOR_ROOT: \(homeEnv)")
}
/**

HOME env: /Users/devzkn/Library/Developer/CoreSimulator/Devices/2499648A-9622-42D9-8931-C342DB0208CC/data/Containers/Data/Application/E0628F2F-2491-4F86-A7D2-3C3375526D60
"IPHONE_SIMULATOR_ROOT"

IPHONE_SIMULATOR_ROOT: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk
*/ return true
}

HOME env: /
IPHONE_SIMULATOR_ROOT: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk

推荐阅读
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
author-avatar
nikechen
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有