libMobileGestalt.dylib crashed when Hooking MGCopyAnswer for ARM64 - hook

When I try to hook MGCopyAnswer, I get a crash. I'm trying this on a jailbroken iPhone 5s in iOS 8.3, arm64 binaries.
#import <substrate.h>
extern "C" CFTypeRef MGCopyAnswer(CFStringRef);
MSHook(CFTypeRef, MGCopyAnswer, CFStringRef key)
{
  return _MGCopyAnswer(key);
}
%ctor
{
  NSString *appID = [[NSBundle mainBundle] bundleIdentifier];
  if ( appID && [appID isEqualToString:#"com.test.test"])   {
    MSHookFunction(MGCopyAnswer, MSHake(MGCopyAnswer));
  }
}
Makefile:
ARCHS = armv7 armv7s arm64
TARGET = iphone:latest:8.0
test2_FRAMEWORKS = UIKit
include theos/makefiles/common.mk
TWEAK_NAME = test2
test2_FILES = Tweak.xm
test2_LIBRARIES = MobileGestalt
include $(THEOS_MAKE_PATH)/tweak.mk
after-install::
  install.exec "killall -9 SpringBoard"
Crash log:
Version: 1.44 (1.4)
Code Type: ARM-64 (Native)
Parent Process: launchd [1]
Date/Time:           2016-04-25 01:09:31.810 +0800
Launch Time:         2016-04-25 01:09:31.564 +0800
OS Version:          iOS 8.3 (12F70)
Report Version:      105
Exception Type:  EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x000000000068fe68
Triggered by Thread:  0
Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libMobileGestalt.dylib          0x0000000195af7e84 0x195af4000 + 16004
1   libMobileGestalt.dylib          0x0000000195af82bc MGGetBoolAnswer + 32
2   AppSupport                      0x000000018b020594 __CPIsInternalDevice_block_invoke + 16
3   libdispatch.dylib               0x0000000196c99950 _dispatch_client_callout + 12
4   libdispatch.dylib               0x0000000196c9a828 dispatch_once_f + 92
5   AppSupport                      0x000000018b02057c CPIsInternalDevice + 60
6   UIKit                           0x0000000189b58750 ___UIApplicationUsesAlternateUI_block_invoke + 12
7   libdispatch.dylib               0x0000000196c99950 _dispatch_client_callout + 12
8   libdispatch.dylib               0x0000000196c9a828 dispatch_once_f + 92
9   UIKit                           0x0000000189923750 UIApplicationInitialize + 1872
10  UIKit                           0x0000000189922b1c UIApplicationMain + 320
MGCopyAnswer:
->  0x193a7fe84 <+0>:  .long  0x002d7c28                ; unknown opcode
    0x193a7fe88 <+4>:  .long  0x00000001                ; unknown opcode
    0x193a7fe8c <+8>:  stp    x20, x19, [sp, #32]
    0x193a7fe90 <+12>: stp    x29, x30, [sp, #48]
    0x193a7fe94 <+16>: add    x29, sp, #48
    0x193a7fe98 <+20>: sub    sp, sp, #48
    0x193a7fe9c <+24>: mov    x19, x1
    0x193a7fea0 <+28>: mov    x22, x0
    0x193a7fea4 <+32>: movz   w0, #0
    0x193a7fea8 <+36>: bl     0x193a7f564               ; ___lldb_unnamed_function54$$libMobileGestalt.dylib
    0x193a7feac <+40>: orr    w1, wzr, #0x1
    0x193a7feb0 <+44>: mov    x0, x22
    0x193a7feb4 <+48>: bl     0x193a7f5fc               ; ___lldb_unnamed_function56$$libMobileGestalt.dylib
    0x193a7feb8 <+52>: mov    x21, x0
    0x193a7febc <+56>: movz   w20, #0
    0x193a7fec0 <+60>: cbz    x21, 0x193a7fefc          ; <+120>
    0x193a7fec4 <+64>: ldr    w20, [x21, #148]
    0x193a7fec8 <+68>: mov    x0, x21
orig_MGCopyAnswer
    0x104234000: movz   x1, #0
    0x104234004: stp    x24, x23, [sp, #-64]!
    0x104234008: stp    x22, x21, [sp, #16]
    0x10423400c: ldr    x16, #8
    0x104234010: br     x16
    0x104234014: .long  0x93a7fe8c                
    0x104234018: .long  0x00000001                ; unknown opcode
What am I doing wrong?

You cannot hook MGCopyAnswer directly because it is too short.
When CydiaSubstrate hooks a C function, it sorts of overwrites an assembly version of goto your_function; at the beginning of the original function. This "goto" in ARM64 is 16 bytes in size, which means if the original function is too short (< 16 bytes), CydiaSubstrate can spill over and corrupt the neighboring functions.
This is exactly why the problem of MGCopyAnswer. The implementation of MGCopyAnswer is basically (on 9.3.2 arm64):
01 00 80 d2 movz x1, #0
01 00 00 14 b MGCopyAnswer_internal
which is just 8 bytes (< 16 bytes) in size. So CydiaSubstrate will corrupt the 8 bytes after the end of MGCopyAnswer.
Unfortunately, MGCopyAnswer_internal is right after MGCopyAnswer, and even worse this function and is called by MGGetBoolAnswer as well. Since MGCopyAnswer_internal is corrupt, you get an EXC_BAD_INSTRUCTION crash inside libMobileGestalt.
A good news for MGCopyAnswer is that, you could just hook MGCopyAnswer_internal! This has an additional benefit that many related functions like MGGetBoolAnswer, MGCopyAnswerWithError, MGCopyMultipleAnswers etc. can respond to your change as well. The bad thing is that MGCopyAnswer_internal is completely internal, and there is no symbols pointing to it. We could rely on the fact that MGCopyAnswer_internal is exactly 8 bytes after MGCopyAnswer on ARM64, and develop this ugly hack:
static CFPropertyListRef (*orig_MGCopyAnswer_internal)(CFStringRef prop, uint32_t* outTypeCode);
CFPropertyListRef new_MGCopyAnswer_internal(CFStringRef prop, uint32_t* outTypeCode) {
return orig_MGCopyAnswer_internal(prop, outTypeCode);
}
extern "C" MGCopyAnswer(CFStringRef prop);
static CFPropertyListRef (*orig_MGCopyAnswer)(CFStringRef prop);
CFPropertyListRef new_MGCopyAnswer(CFStringRef prop) {
return orig_MGCopyAnswer(prop);
}
%ctor {
uint8_t MGCopyAnswer_arm64_impl[8] = {0x01, 0x00, 0x80, 0xd2, 0x01, 0x00, 0x00, 0x14};
const uint8_t* MGCopyAnswer_ptr = (const uint8_t*) MGCopyAnswer;
if (memcmp(MGCopyAnswer_ptr, MGCopyAnswer_arm64_impl, 8) == 0) {
MSHookFunction(MGCopyAnswer_ptr + 8, (void*)new_MGCopyAnswer_internal, (void**)&orig_MGCopyAnswer_internal);
} else {
MSHookFunction(MGCopyAnswer_ptr, (void*)new_MGCopyAnswer, (void**)&orig_MGCopyAnswer);
}
}
(This only checks for arm64 on 9.3.2. Other platforms may crash in different ways, and have different assembly code, so you may need to add additional conditions into enter the hook-MGCopyAnswer_internal branch. YMMV!)

Try this code:
#import <substrate.h>
static CFTypeRef (*orig_MGCopyAnswer)(CFStringRef str);
CFTypeRef new_MGCopyAnswer(CFStringRef str)
{
return orig_MGCopyAnswer(str);
}
%ctor
{
NSString *appID = [[NSBundle mainBundle] bundleIdentifier];
if ( appID && [appID isEqualToString:#"com.test.test"]) {
void * MGCopyAnswerFn = MSFindSymbol(NULL, "_MGCopyAnswer");
MSHookFunction(MGCopyAnswerFn, (void *) new_MGCopyAnswer, (void **)& orig_MGCopyAnswer);
}
}

Related

After reboot, on resumption of uncompression, inflate() is reporting Z_DATA_ERROR

Thanks Mark, on resumption, now I get Z_DATA_ERROR
case STORED:
strm->msg = (char *)"invalid stored block lengths"; // got here - Anton
state->mode = BAD;
Just to see I understood your suggestions yesterday:
after inflateInit2()
// go to byte offset
ZSEEK64( , , streamCurrentPos, ZLIB_FILEFUNC_SEEK_SET)
if ( streamBits > 0 )
{
// get that byte
unz64local_getByte( , , &aByte)
// and shift down by the number of bits. This API doing it?
inflatePrime ( , streamBits, 8 - streamBits)
} else { no bits to insert }
inflateSetDictionary ()
And state of uncompression is saved like this:
typedef struct state_of_uncompression
{
ZPOS64_T streamCurrentPos; // from : unzGetCurrentFileZStreamPos64()
int streamBits; // from : stream.data_type & (~0x1C0), after clearing bits 8,7, and 6
Byte dictionary_buf[32768]; // from : inflateGetDictionary()
uInt dictLength; // from : inflateGetDictionary();
uint64_t output_wrt_offset // got this already.
} uncompression_state_info;
What? No.
inflatePrime ( , streamBits, 8 - streamBits) makes no sense. And you did nothing with the aByte you got.
It should be inflatePrime(strm, streamBits, aByte >> (8 - streamBits)).

Why does this FTDI function return zero for the fthandle?

I have a FTDI USB3 development board and some FTDI provided code for accessing it. The code works fine for things like the Device number, VID/PID etc. but always returns zero for the 'ftHandle'. As the handle is required for driving the board, this is not helpful! Can anyone see why this should happen?
static FT_STATUS displayDevicesMethod2(void)
{
FT_STATUS ftStatus;
FT_HANDLE ftHandle = NULL;
// Get and display the list of devices connected
// First call FT_CreateDeviceInfoList to get the number of connected devices.
// Then either call FT_GetDeviceInfoList or FT_GetDeviceInfoDetail to display device
info.
// Device info: Flags (usb speed), device type (600 e.g.), device ID (vendor,
product),
handle for subsequent data access.
DWORD numDevs = 0;
ftStatus = FT_CreateDeviceInfoList(&numDevs); // Build a list and return number
connected.
if (FT_FAILED(ftStatus))
{
printf("Failed to create a device list, status = %d\n", ftStatus);
}
printf("Successfully created a device list.\n\tNumber of connected devices: %d\n",
numDevs);
// Method 2: using FT_GetDeviceInfoDetail
if (!FT_FAILED(ftStatus) && numDevs > 0)
{
ftHandle = NULL;
DWORD Flags = 0;
DWORD Type = 0;
DWORD ID = 0;
char SerialNumber[16] = { 0 };
char Description[32] = { 0 };
for(DWORD i = 0; i <numDevs; i++)
{
ftStatus = FT_GetDeviceInfoDetail(i, &Flags, &Type, &ID, NULL, SerialNumber,
Description, &ftHandle);
if (!FT_FAILED(ftStatus))
{
printf("Device[%d] (using FT_GetDeviceInfoDetail)\n", i);
printf("\tFlags: 0x%x %s | Type: %d | ID: 0x%08X | ftHandle=0x%p\n",
Flags,
Flags & FT_FLAGS_SUPERSPEED? "[USB 3]":
Flags & FT_FLAGS_HISPEED? "[USB 2]":
Flags & FT_FLAGS_OPENED? "[OPENED]": "",
Type,
ID,
ftHandle);
printf("\tSerialNumber=%s\n", SerialNumber);
printf("\tDescription=%s\n", Description);
}
}
}
return ftStatus;
}
This is indeed not super straight forward, but a short peek in the FTDI Knowledgebase yields:
This function builds a device information list and returns the number of D2XX devices connected to the system. The list contains information about both unopen and open devices.
A handle only exists for an opened device. Thus, I assume that your code does not already include that step. If so you need to open it first, e.g. using FT_Open. There are plenty of examples available. You can check their page or stackoverflow for a working example.

why CreateRemoteThread cause inject target crash

Update on 2019/11/19:
I search google and find a lib to do this(I can't remember which is it now), and it works fine.
Update on 2019/6/19:
My env is win10, the reason is this code is not work on win10?
Origin:
I use this code to just inject int foo() {return 0} to a target process. But It cause target process crash.
The entire vs solution is here: https://github.com/huhuang03/test/tree/master/win/InjectHelloWorld. Include the InjectMe and InjectByCode.
char hand_asm[100] = {0xC3}; // 0xc3 is the retn assembly
if (!WriteProcessMemory(h_target, targetFuncSpace, &hand_asm, CODE_SPACE_SIZE, NULL)) {
showError(L"Cna't write targetFuncSpace");
return EXIT_FAILURE;
}
InjectFuncParam param;
LPVOID injectFuncParamSpace = VirtualAllocEx(h_target, NULL, sizeof(param), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!injectFuncParamSpace) {
showError(L"Can't alloc injectFuncParamSpace");
return EXIT_FAILURE;
}
system("pause");
DWORD remoteThreadId = 0;
HANDLE h_remoteThread = CreateRemoteThread(h_target, NULL, 0, (LPTHREAD_START_ROUTINE)targetFuncSpace, injectFuncParamSpace, 0, &remoteThreadId);
if (!h_remoteThread) {
VirtualFreeEx(h_target, injectFuncParamSpace, 0, MEM_RELEASE);
VirtualFreeEx(h_target, targetFuncSpace, 0, MEM_RELEASE);
showError(L"Cant' create rmeote Thread");
return EXIT_FAILURE;
this cause InjectMe crash, I can't find a way to debug this.
By the way, I use ollydbg to set a breakpoint at targetFuncSpace, but the ollydbg says it's not code segment... Why, I had use the PAGE_EXECUTE_READWRITE to alloc the space.
One problem I see is you can't VirtualFree targetFuncSpace until the remote thread in the target process has finished executing.
Also WriteProcessMemory is copying CODE_SPACE_SIZE (4096) bytes from hand_asm which is only 100 bytes.

Beaglebone am335x accessing GPIO by mmap, set and clear pin

I'm writing a simple program to set and clear a pin (the purpose is to use that pin as a custom spi_CS).
I'm able to export that pin (gpio1_17, port 9 pin 23 bb white) and to use that trough the filesystem but I have to drive it faster.
This is the code:
uint32_t *gpio;
int fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd < 0){
fprintf(stderr, "Unable to open port\n\r");
exit(fd);
}
gpio =(uint32_t *) mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO1_offset); // start of GPIOA
if(gpio == (void *) -1) {
printf("Memory map failed.\n");
exit(0);
} else {
printf("Memory mapped at address %p.\n", gpio);
}
printf("\nGPIO_OE:%X\n",gpio[GPIO_OE/4]);
gpio[GPIO_OE/4]=USR1;
printf("\nGPIO_OE:%X\n",gpio[GPIO_OE/4]);
printf("\nGPIO_CLEARDATAOUT:%X\n",gpio[GPIO_CLEARDATAOUT/4]);
gpio[GPIO_CLEARDATAOUT/4]=USR1;
printf("\nGPIO_CLEARDATAOUT:%X\n",gpio[GPIO_CLEARDATAOUT/4]);
sleep(1);
printf("\nGPIO_SETDATAOUT%X\n",gpio[GPIO_SETDATAOUT/4]);
gpio[GPIO_DATAOUT/4]=USR1;
printf("\nGPIO_SETDATAOUT%X\n",gpio[GPIO_SETDATAOUT/4]);
with
#define GPIO1_offset 0x4804c000
#define GPIO1_size 0x4804cfff-GPIO1_offset
#define GPIO_OE 0x134
#define GPIO_SETDATAOUT 0x194
#define GPIO_CLEARDATAOUT 0x190
#define GPIO_DATAOUT 0x13C
#define USR1 1<<17
I'm able to outputenable that pin, beacuse if I put it high before running the program, that ping goes low. But I cannot set and reset it. Any ideas?
Why are you directly modifying the registers? It is way easier to just use it as a linux GPIO:
#define GPIO_1_17 "49"
int gpio;
status_codes stat = STATUS_SUCCESS;
//Export our GPIOs for use
if((gpio = open("/sys/class/gpio/export", O_WRONLY)) >= 0) {
write(gpio, GPIO_1_17, strlen(GPIO_1_17));
close(gpio);
} else {
stat = STATUS_GPIO_ACCESS_FAILURE;
break;
}
//Set the direction and pull low
if((gpio = open("/sys/class/gpio/gpio" GPIO_1_17 "/direction", O_WRONLY)) >= 0) {
write(gpio, "out", 3); // Set out direction
close(gpio);
} else {
stat = STATUS_GPIO_ACCESS_FAILURE;
break;
}
if((gpio = open("/sys/class/gpio/gpio" GPIO_1_17 "/value", O_WRONLY)) >= 0) {
write(gpio, "0", 1); // Pull low
close(gpio);
} else {
stat = STATUS_GPIO_ACCESS_FAILURE;
break;
}
Then just make sure it is muxed as a gpio in your inits.
As far as the mmap method you have above you addressing looks correct. The addresses in the ref manual are byte addresses and you are using a 32-bit pointer so what you have there is correct. However, this line: gpio[GPIO_OE/4]=USR1 makes every pin on GPIO1 an output except for 17 which it makes an input (0 = output and 1 = input). You probably meant this: gpio[GPIO_OE/4] &= ~USR1
Also i believe you meant to have gpio[GPIO_SETDATAOUT/4]=USR1; instead of gpio[GPIO_DATAOUT/4]=USR1; They will both cause GPIO1_17 to be set; however, using what you have will also set all the other pins on GPIO1 to be 0.
I would definitely recommend using the designed kernel interfaces because mmap'ing stuff that is also controlled by the kernel can be asking for trouble.
Good Luck! : )
EDIT: My bad just realized you said why you were not driving it directly through the file system because you needed to drive it faster! You may also want to consider writing/modifying the SPI driver so that the stuff is being done in Kernel land if speed is what your after. The omap gpio interfaces are simple to use there as well, just request and set : ).

Strange noise and abnormalities when writing audio data from libspotify into a file

Currently we're implementing Libspotify in a win 7 64 bit system. Everything seems to work fine except the playback. We get data from the callback , but even using audicity on the saved audio, is filled with abnormalities. So to research further we took the win32 sample (spshell ) and modified it to save the music data to file. Same problem, definitely music with these ticks in it. I'm sure there's something simple I'm missing here, but I'm at a loss as to what could be the problem. Any help would be great since as it stands our project is at a stand still until we can resolve this.
The audio saved can be viewed here
http://uploader.crestron.com/download.php?file=8001d80992480280dba365752aeaca81
Below are the code changes I made to save the file ( for testing only )
static FILE *pFile;
int numBytesToWrite=0;
CRITICAL_SECTION m_cs;
int SP_CALLCONV music_delivery(sp_session *s, const sp_audioformat *fmt, const void *frames, int num_frames)
{
if ( num_frames == 0 )
return;
EnterCriticalSection(&m_cs);
numBytesToWrite = ( num_frames ) * fmt->channels * sizeof(short);
if (numBytesToWrite > 0 )
fwrite(frames, sizeof(short), numBytesToWrite, pFile);
LeaveCriticalSection(&m_cs);
return num_frames;
}
static void playtrack_test(void)
{
sp_error err;
InitializeCriticalSection(&m_cs);
pFile = fopen ("C:\\zzzspotify.pcm","wb");
test_start(&playtrack);
if((err = sp_session_player_load(g_session, stream_track)) != SP_ERROR_OK) {
test_report(&playtrack, "Unable to load track: %s", sp_error_message(err));
return;
}
info_report("Streaming '%s' by '%s' this will take a while", sp_track_name(stream_track),
sp_artist_name(sp_track_artist(stream_track, 0)));
sp_session_player_play(g_session, 1);
}
void SP_CALLCONV play_token_lost(sp_session *s)
{
fclose(pFile);
DeleteCriticalSection(&m_cs);
stream_track_end = 2;
notify_main_thread(g_session);
info_report("Playtoken lost");
}
static int check_streaming_done(void)
{
if(stream_track_end == 2)
test_report(&playtrack, "Playtoken lost");
else if(stream_track_end == 1)
test_ok(&playtrack);
else
return 0;
fclose(pFile);
stream_track_end = 0;
return 1;
}
It looks like this is the problem:
fwrite(frames, sizeof(short), numBytesToWrite, pFile);
The fwrite documentation states that the second argument is the "size in bytes of each element to be written", and the third is this "number of elements, each one with a size of size bytes".
The way you're calling frwritewill tell it to write numBytesToWrite * sizeof(short) bytes, which will run right off the end of the given buffer. I'm actually surprised it doesn't crash!
I'd suggest changing your fwrite call to something like:
fwrite(frames, sizeof(char), numBytesToWrite, pFile);
or:
int numSamplesToWrite = num_frames * fmt->channels;
fwrite(frames, sizeof(short), numSamplesToWrite, pFile);
Edit:
After looking at your audio in detail, I'm more convinced that this is the case. The song seems to be playing at half speed (i.e., 2x as much data is being written) and the artefacts seem to look like buffer overrun into random memory.

Resources