利用setcontext来进行ORW

当遇到堆题禁用execve时我们就需要用ORW的方法来读取flag,那么堆题如何实现栈迁移来进行ORW就成了一个问题,而利用setcontext是解决这个问题的一个方案

首先来了解什么是setcontext?

setcontext是libc中的一个函数,而它的汇编代码中含有大量的 mov <寄存器> 这类汇编语句,如下图(注:setcontext以glibc2.29为分界线,2.29以下和2.29及以上有较大不同):
![[Pasted image 20250227233231.png]]

上图是glibc2.27中的 setcontext 的汇编部分,可以看到其中有非常多的控制寄存器的mov指令,它们都利用 rdi+<偏移值> 来获取具体的数值,所以如果我们可以控制 rdi寄存器 随后将程序跳转到 setcontext+53(也就是图中mov rsp,[rdi+0xa0h]的位置) 这样我们就可以控制包括 rip rsp 这两个重要寄存器,

基本思路

控制执行流之后就有两种思路:

  1. 是直接控制程序执行流去执行ROP链
  2. 是先用 mprotect 函数开辟一段可读可写可执行的空间再跳到上面去执行 shellcode

这里我们主要讲解执行ROP链ORW的思路:
控制 rsp寄存器 到我们布置好 ROP的地址,然后控制 ripret地址

如何控制rip并开始ORW?

通过观察上图发现最后一条指令是ret而其中有一个push rcx的操作,因此可以判断ret返回的地方就是rcx中存储的地址
那么此时栈中的情况就是下面的这样

ORW部分的代码
... ...
ORW部分的代码
rcx中的值  <-- rsp

-----我是分割线----
<think>好的,用户提到他们的代码中没有setContext方法,这导致在测试时无法直接注入模拟的Context。这时候需要找到其他方式来注入Context,比如使用反射或者重构代码。 首先,我需要确认TimeManager类是如何获取Context的。通常,Android中的单例或管理类可能会通过构造函数传入Context,或者使用静态方法初始化。如果TimeManager有一个构造函数接受Context参数,那在测试时可以直接创建实例并传入模拟的Context。如果没有的话,可能需要使用反射来修改私有字段。 用户之前的问题中提到了使用反射来注入mContext,但可能他们现在需要更详细的步骤或者替代方案。如果构造函数可行的话,这会是更简单的方法。例如,在测试中创建TimeManager实例时传入mockContext,这样就不需要处理反射了。 如果构造函数不可行,那么必须使用反射。反射需要处理异常,并且可能因为字段名称错误或访问权限问题导致失败。需要确保字段名称正确,并且设置setAccessible(true)来绕过访问限制。 另外,考虑到测试的稳定性,使用反射可能增加测试的复杂性,但这是常见的做法,尤其是在遗留代码中。用户可能需要了解如何正确使用反射来注入依赖,同时避免在生产代码中引入不必要的setter方法。 最后,还需要确保SettingUtils的静态方法被正确模拟,并且验证调用是否正确。结合之前的测试用例,用户需要调整代码以正确注入Context,无论是通过构造函数还是反射。 </think>针对`TimeManager`没有`setContext`方法的情况,可以通过**反射注入`mContext`字段**,以下是完整解决方案: ```java @Test public void testSetWatchSwitch_withReflection() { // 1. 创建Context模拟对象 Context mockContext = mock(Context.class); // 2. 创建TimeManager实例 TimeManager timeManager = new TimeManager(); // 3. 使用反射注入mContext字段 try { // 获取私有字段 Field contextField = TimeManager.class.getDeclaredField("mContext"); // 打破访问权限 contextField.setAccessible(true); // 注入模拟对象 contextField.set(timeManager, mockContext); } catch (NoSuchFieldException | IllegalAccessException e) { // 异常处理 fail("反射注入mContext失败: " + e.getMessage()); } // 4. 模拟SettingUtils的静态方法 try (MockedStatic<SettingUtils> mockedStatic = mockStatic(SettingUtils.class)) { // 5. 设置监听器 TimeChangeListener mockListener = mock(TimeChangeListener.class); timeManager.setTimeChangeListener(mockListener); // 6. 执行测试逻辑 timeManager.setWatchSwitch(true); // 7. 验证静态方法调用 verifyStatic(); SettingUtils.putGlobalInteger(mockContext, TIME_MANAGER_WATCH_SWITCH, 1); // 8. 验证监听器回调 verify(mockListener).onWatchSwitchChanged(true); } } ``` --- ### 关键问题解决点 | 问题 | 解决方案 | 说明 | |------|----------|------| | **无setContext方法** | 使用反射注入私有字段 | 通过`Field.setAccessible(true)`强制访问私有字段 | | **静态方法调用** | 使用`mockStatic`模拟 | 需要Mockito 3.4+支持 | | **日志验证** | 可选的静态方法模拟 | `Log.i(TAG, ...)`可通过`mockStatic(Log.class)`验证 | | **异常处理** | 显式捕获反射异常 | 反射失败时立即终止测试 | --- ### 替代方案:重构建议 如果允许修改生产代码,建议添加构造函数注入: ```java // 修改TimeManager类 public class TimeManager { private Context mContext; // 新增构造函数 public TimeManager(Context context) { this.mContext = context; } // 旧无参构造函数(可保留兼容旧代码) public TimeManager() { this(/* 默认值 */); } } ``` 测试代码简化为: ```java @Test public void testSetWatchSwitch_withConstructorInjection() { Context mockContext = mock(Context.class); TimeManager timeManager = new TimeManager(mockContext); // 直接注入 // 后续测试逻辑同上 } ``` --- ### 测试边界条件 1. **空Context注入** ```java @Test(expected = NullPointerException.class) public void testConstructor_withNullContext_shouldThrow() { new TimeManager(null); // 应该抛出异常 } ``` 2. **多次调用setWatchSwitch** ```java @Test public void testSetWatchSwitch_multipleCalls() { // ...初始化代码 timeManager.setWatchSwitch(true); timeManager.setWatchSwitch(false); InOrder inOrder = inOrder(mockListener); inOrder.verify(mockListener).onWatchSwitchChanged(true); inOrder.verify(mockListener).onWatchSwitchChanged(false); } ``` ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值