Skip to content

Commit

Permalink
Add code injection for far-away branching for arm64
Browse files Browse the repository at this point in the history
This is implemented using "emulation" by using breakpoints so Bit Slicer can modify the program counter to jump to and back from the island that has the newly injected code.

There is still quite a bit of polish/implementation work need to be done.
  • Loading branch information
zorgiepoo committed Oct 10, 2022
1 parent d8867e3 commit c8fa9b3
Show file tree
Hide file tree
Showing 12 changed files with 489 additions and 148 deletions.
6 changes: 6 additions & 0 deletions Bit Slicer.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
726CA2D419606E3100A6AD40 /* Search Options.xib in Resources */ = {isa = PBXBuildFile; fileRef = 726CA2D619606E3100A6AD40 /* Search Options.xib */; };
726CA2D719606E3800A6AD40 /* Watch Variable Dialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 726CA2D919606E3800A6AD40 /* Watch Variable Dialog.xib */; };
727151DB28E92E9D003B7DD0 /* ZGPyArchModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 727151DA28E92E9D003B7DD0 /* ZGPyArchModule.m */; };
727151F128F28554003B7DD0 /* ZGCodeInjectionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 727151F028F28554003B7DD0 /* ZGCodeInjectionHandler.m */; };
7275F8A51BA4756100FD144C /* ZGNullability.m in Sources */ = {isa = PBXBuildFile; fileRef = 7275F8A41BA4756100FD144C /* ZGNullability.m */; };
7275F8A61BA4BD7200FD144C /* ZGNullability.m in Sources */ = {isa = PBXBuildFile; fileRef = 7275F8A41BA4756100FD144C /* ZGNullability.m */; };
7278DC041E4A967700C37150 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7278DC031E4A967700C37150 /* Sparkle.framework */; };
Expand Down Expand Up @@ -462,6 +463,8 @@
726CA2D819606E3800A6AD40 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Base.lproj/Watch Variable Dialog.xib"; sourceTree = "<group>"; };
727151D928E92E9D003B7DD0 /* ZGPyArchModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ZGPyArchModule.h; path = "Bit Slicer/ZGPyArchModule.h"; sourceTree = "<group>"; };
727151DA28E92E9D003B7DD0 /* ZGPyArchModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ZGPyArchModule.m; path = "Bit Slicer/ZGPyArchModule.m"; sourceTree = "<group>"; };
727151EF28F28554003B7DD0 /* ZGCodeInjectionHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ZGCodeInjectionHandler.h; path = "Bit Slicer/ZGCodeInjectionHandler.h"; sourceTree = "<group>"; };
727151F028F28554003B7DD0 /* ZGCodeInjectionHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ZGCodeInjectionHandler.m; path = "Bit Slicer/ZGCodeInjectionHandler.m"; sourceTree = "<group>"; };
7275F8A31BA4756100FD144C /* ZGNullability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ZGNullability.h; path = "Bit Slicer/ZGNullability.h"; sourceTree = "<group>"; };
7275F8A41BA4756100FD144C /* ZGNullability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ZGNullability.m; path = "Bit Slicer/ZGNullability.m"; sourceTree = "<group>"; };
7278DC031E4A967700C37150 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = deps/Sparkle/Sparkle.framework; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1143,6 +1146,8 @@
77F1165817D2F001009E002A /* ZGRegister.m */,
77F1165A17D2F00A009E002A /* ZGCodeInjectionWindowController.h */,
77F1165B17D2F00A009E002A /* ZGCodeInjectionWindowController.m */,
727151EF28F28554003B7DD0 /* ZGCodeInjectionHandler.h */,
727151F028F28554003B7DD0 /* ZGCodeInjectionHandler.m */,
);
name = Debugger;
sourceTree = "<group>";
Expand Down Expand Up @@ -1677,6 +1682,7 @@
720844FA24E0715C00F3D449 /* DataInspector.m in Sources */,
770FABB118490DB400C176B7 /* ZGEditAddressWindowController.m in Sources */,
77FFC14C18711D2700122357 /* ZGEditDescriptionWindowController.m in Sources */,
727151F128F28554003B7DD0 /* ZGCodeInjectionHandler.m in Sources */,
772C0F7E18B88AFA009FFF72 /* ZGRegisterEntries.m in Sources */,
72DBC9541B77B84D0092ED75 /* ZGPrivateCoreSymbolicator.m in Sources */,
777C34B5187523D0005E64E1 /* ZGNoSmallSizeToolbar.m in Sources */,
Expand Down
1 change: 1 addition & 0 deletions Bit Slicer/ZGBreakPoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, nullable) NSError *error;
@property (nonatomic) ZGMemoryProtection originalProtection;
@property (nonatomic) ZGRegistersState *registersState;
@property (nonatomic) BOOL emulated;

@end

Expand Down
1 change: 1 addition & 0 deletions Bit Slicer/ZGBreakPointController.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process callback:(PyObject *)callback delegate:(id)delegate;
- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process thread:(thread_act_t)thread basePointer:(ZGMemoryAddress)basePointer callback:(PyObject *)callback delegate:(id)delegate;
- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process thread:(thread_act_t)thread basePointer:(ZGMemoryAddress)basePointer delegate:(id)delegate;
- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process emulated:(BOOL)emulated delegate:(id)delegate;
- (ZGBreakPoint * _Nullable)removeBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process;
- (void)resumeFromBreakPoint:(ZGBreakPoint *)breakPoint;
- (ZGBreakPoint *)addSingleStepBreakPointFromBreakPoint:(ZGBreakPoint *)breakPoint;
Expand Down
16 changes: 11 additions & 5 deletions Bit Slicer/ZGBreakPointController.m
Original file line number Diff line number Diff line change
Expand Up @@ -1120,25 +1120,30 @@ - (BOOL)addWatchpointOnVariable:(ZGVariable *)variable inProcess:(ZGProcess *)pr

- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process callback:(PyObject *)callback delegate:(id)delegate
{
return [self addBreakPointOnInstruction:instruction inProcess:process thread:0 basePointer:0 hidden:NO condition:NULL callback:callback delegate:delegate];
return [self addBreakPointOnInstruction:instruction inProcess:process thread:0 basePointer:0 hidden:NO emulated:NO condition:NULL callback:callback delegate:delegate];
}

- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process condition:(PyObject *)condition delegate:(id)delegate
{
return [self addBreakPointOnInstruction:instruction inProcess:process thread:0 basePointer:0 hidden:NO condition:condition callback:NULL delegate:delegate];
return [self addBreakPointOnInstruction:instruction inProcess:process thread:0 basePointer:0 hidden:NO emulated:NO condition:condition callback:NULL delegate:delegate];
}

- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process thread:(thread_act_t)thread basePointer:(ZGMemoryAddress)basePointer delegate:(id)delegate
{
return [self addBreakPointOnInstruction:instruction inProcess:process thread:thread basePointer:basePointer hidden:YES condition:NULL callback:NULL delegate:delegate];
return [self addBreakPointOnInstruction:instruction inProcess:process thread:thread basePointer:basePointer hidden:YES emulated:NO condition:NULL callback:NULL delegate:delegate];
}

- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process thread:(thread_act_t)thread basePointer:(ZGMemoryAddress)basePointer callback:(PyObject *)callback delegate:(id)delegate
{
return [self addBreakPointOnInstruction:instruction inProcess:process thread:thread basePointer:basePointer hidden:YES condition:NULL callback:callback delegate:delegate];
return [self addBreakPointOnInstruction:instruction inProcess:process thread:thread basePointer:basePointer hidden:YES emulated:NO condition:NULL callback:callback delegate:delegate];
}

- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process thread:(thread_act_t)thread basePointer:(ZGMemoryAddress)basePointer hidden:(BOOL)isHidden condition:(PyObject *)condition callback:(PyObject *)callback delegate:(id)delegate
- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process emulated:(BOOL)emulated delegate:(id)delegate
{
return [self addBreakPointOnInstruction:instruction inProcess:process thread:0 basePointer:0 hidden:NO emulated:emulated condition:NULL callback:NULL delegate:delegate];
}

- (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGProcess *)process thread:(thread_act_t)thread basePointer:(ZGMemoryAddress)basePointer hidden:(BOOL)isHidden emulated:(BOOL)emulated condition:(PyObject *)condition callback:(PyObject *)callback delegate:(id)delegate
{
if (![self setUpExceptionPortForProcess:process])
{
Expand Down Expand Up @@ -1189,6 +1194,7 @@ - (BOOL)addBreakPointOnInstruction:(ZGInstruction *)instruction inProcess:(ZGPro

breakPoint.variable = variable;
breakPoint.hidden = isHidden;
breakPoint.emulated = emulated;
breakPoint.thread = thread;
breakPoint.basePointer = basePointer;
#if TARGET_CPU_ARM64
Expand Down
56 changes: 56 additions & 0 deletions Bit Slicer/ZGCodeInjectionHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2022 Mayur Pawashe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the project's author nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#import <Foundation/Foundation.h>
#import "ZGProcessTypes.h"
#import "ZGBreakPointDelegate.h"

@class ZGProcess;
@class ZGInstruction;
@class ZGBreakPointController;

NS_ASSUME_NONNULL_BEGIN

@interface ZGCodeInjectionHandler : NSObject <ZGBreakPointDelegate>

@property (nonatomic, readonly, nullable) ZGInstruction *toIslandInstruction;
@property (nonatomic, readonly, nullable) ZGInstruction *fromIslandInstruction;
@property (nonatomic, readonly) ZGMemoryAddress islandAddress;

- (BOOL)addBreakPointWithToIslandInstruction:(ZGInstruction *)toIslandInstruction fromIslandInstruction:(ZGInstruction *)fromIslandInstruction islandAddress:(ZGMemoryAddress)islandAddress process:(ZGProcess *)process processType:(ZGProcessType)processType breakPointController:(ZGBreakPointController *)breakPointController;

- (void)removeBreakPoints;

@end


NS_ASSUME_NONNULL_END
115 changes: 115 additions & 0 deletions Bit Slicer/ZGCodeInjectionHandler.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright (c) 2022 Mayur Pawashe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the project's author nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#import "ZGCodeInjectionHandler.h"
#import "ZGBreakPointController.h"
#import "ZGBreakPoint.h"
#import "ZGInstruction.h"
#import "ZGVariable.h"
#import "ZGDebugLogging.h"
#import "ZGRegistersState.h"
#import "ZGProcess.h"
#import "ZGVirtualMemory.h"

@implementation ZGCodeInjectionHandler
{
ZGBreakPointController *_breakPointController;
ZGInstruction *_toIslandInstruction;
ZGInstruction *_fromIslandInstruction;
ZGMemoryAddress _islandAddress;
ZGProcessType _processType;
ZGProcess *_process;
}

- (BOOL)addBreakPointWithToIslandInstruction:(ZGInstruction *)toIslandInstruction fromIslandInstruction:(ZGInstruction *)fromIslandInstruction islandAddress:(ZGMemoryAddress)islandAddress process:(ZGProcess *)process processType:(ZGProcessType)processType breakPointController:(ZGBreakPointController *)breakPointController
{
_breakPointController = breakPointController;
_toIslandInstruction = toIslandInstruction;
_fromIslandInstruction = fromIslandInstruction;
_islandAddress = islandAddress;
_processType = processType;
_process = process;

if (![breakPointController addBreakPointOnInstruction:toIslandInstruction inProcess:process emulated:YES delegate:self])
{
return NO;
}

if (![breakPointController addBreakPointOnInstruction:fromIslandInstruction inProcess:process emulated:YES delegate:self])
{
[breakPointController removeBreakPointOnInstruction:toIslandInstruction inProcess:process];
return NO;
}

return YES;
}

- (void)removeBreakPoints
{
if (_fromIslandInstruction != nil)
{
[_breakPointController removeBreakPointOnInstruction:_fromIslandInstruction inProcess:_process];
_fromIslandInstruction = nil;
}

if (_toIslandInstruction != nil)
{
[_breakPointController removeBreakPointOnInstruction:_toIslandInstruction inProcess:_process];
_toIslandInstruction = nil;
}
}

- (void)breakPointDidHit:(ZGBreakPoint *)breakPoint
{
ZGMemoryAddress breakPointAddress = breakPoint.variable.address;
ZGMemoryMap processTask = _process.processTask;

zg_thread_state_t threadState;
mach_msg_type_number_t threadStateCount;
thread_act_t thread = breakPoint.thread;
if (!ZGGetGeneralThreadState(&threadState, thread, &threadStateCount))
{
ZG_LOG(@"Error: failed to retrieve general thread state set in code injection breakpoint handler");
ZGResumeTask(processTask);
return;
}

ZGMemoryAddress newInstructionAddress = (breakPointAddress == _toIslandInstruction.variable.address) ? _islandAddress : (_toIslandInstruction.variable.address + _toIslandInstruction.variable.size);

ZGSetInstructionPointerFromGeneralThreadState(&threadState, newInstructionAddress, _processType);

ZGSetGeneralThreadState(&threadState, thread, threadStateCount);

ZGResumeTask(processTask);
}

@end
5 changes: 3 additions & 2 deletions Bit Slicer/ZGCodeInjectionWindowController.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@

@class ZGProcess;
@class ZGInstruction;
@class ZGBreakPoint;
@class ZGBreakPointController;
@class ZGCodeInjectionHandler;

NS_ASSUME_NONNULL_BEGIN

@interface ZGCodeInjectionWindowController : NSWindowController

- (void)attachToWindow:(NSWindow *)parentWindow process:(ZGProcess *)process processType:(ZGProcessType)processType instruction:(ZGInstruction *)instruction breakPoints:(NSArray<ZGBreakPoint *> *)breakPoints undoManager:(nullable NSUndoManager *)undoManager;
- (void)attachToWindow:(NSWindow *)parentWindow process:(ZGProcess *)process processType:(ZGProcessType)processType instruction:(ZGInstruction *)instruction breakPointController:(ZGBreakPointController *)breakPointController undoManager:(nullable NSUndoManager *)undoManager completionHandler:(void (^)(ZGCodeInjectionHandler * _Nullable))completionHandler;

@end

Expand Down
Loading

0 comments on commit c8fa9b3

Please sign in to comment.