热门标签 | 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

推荐阅读
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • Java 类成员初始化顺序与数组创建
    本文探讨了Java中类成员的初始化顺序、静态引入、可变参数以及finalize方法的应用。通过具体的代码示例,详细解释了这些概念及其在实际编程中的使用。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • 在使用 DataGridView 时,如果在当前单元格中输入内容但光标未移开,点击保存按钮后,输入的内容可能无法保存。只有当光标离开单元格后,才能成功保存数据。本文将探讨如何通过调用 DataGridView 的内置方法解决此问题。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
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社区 版权所有