mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-16 01:38:20 +00:00
331 lines
18 KiB
Markdown
331 lines
18 KiB
Markdown
# macOS MIG - Mach Interface Generator
|
|
|
|
<details>
|
|
|
|
<summary><strong>जानें AWS हैकिंग को शून्य से हीरो तक</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong> के साथ!</strong></summary>
|
|
|
|
HackTricks का समर्थन करने के अन्य तरीके:
|
|
|
|
* यदि आप अपनी **कंपनी का विज्ञापन HackTricks में देखना चाहते हैं** या **HackTricks को PDF में डाउनलोड करना चाहते हैं** तो [**सब्सक्रिप्शन प्लान**](https://github.com/sponsors/carlospolop) देखें!
|
|
* [**आधिकारिक PEASS और HackTricks स्वैग**](https://peass.creator-spring.com) प्राप्त करें
|
|
* हमारे विशेष [**NFTs**](https://opensea.io/collection/the-peass-family) संग्रह, [**The PEASS Family**](https://opensea.io/collection/the-peass-family) खोजें
|
|
* **शामिल हों** 💬 [**डिस्कॉर्ड समूह**](https://discord.gg/hRep4RUj7f) या [**टेलीग्राम समूह**](https://t.me/peass) या हमें **ट्विटर** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live) **पर फॉलो** करें।
|
|
* **अपने हैकिंग ट्रिक्स साझा करें, HackTricks** और [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos में PRs सबमिट करके।
|
|
|
|
</details>
|
|
|
|
MIG को **Mach IPC** कोड निर्माण की प्रक्रिया को सरल बनाने के लिए बनाया गया था। यह मौजूदा परिभाषा के साथ सर्वर और क्लाइंट के बीच संचार के लिए आवश्यक कोड उत्पन्न करता है। यदी उत्पन्न कोड बेहद बेहद भद्दा हो, तो एक डेवलपर को उसे आयात करने की आवश्यकता होगी और उसका कोड पहले की तुलना में बहुत सरल होगा।
|
|
|
|
### उदाहरण
|
|
|
|
एक परिभाषा फ़ाइल बनाएं, इस मामले में एक बहुत ही सरल फ़ंक्शन के साथ:
|
|
|
|
{% code title="myipc.defs" %}
|
|
```cpp
|
|
subsystem myipc 500; // Arbitrary name and id
|
|
|
|
userprefix USERPREF; // Prefix for created functions in the client
|
|
serverprefix SERVERPREF; // Prefix for created functions in the server
|
|
|
|
#include <mach/mach_types.defs>
|
|
#include <mach/std_types.defs>
|
|
|
|
simpleroutine Subtract(
|
|
server_port : mach_port_t;
|
|
n1 : uint32_t;
|
|
n2 : uint32_t);
|
|
```
|
|
{% endcode %}
|
|
|
|
अब mig का उपयोग करें ताकि सर्वर और क्लाइंट कोड उत्पन्न किया जा सके जो एक-दूसरे के भीतर संवाद करने के लिए सक्षम हों और Subtract फ़ंक्शन को कॉल कर सकें:
|
|
```bash
|
|
mig -header myipcUser.h -sheader myipcServer.h myipc.defs
|
|
```
|
|
कई नए फ़ाइलें मौजूदा निर्देशिका में बनाई जाएगी।
|
|
|
|
फ़ाइलों **`myipcServer.c`** और **`myipcServer.h`** में आपको संरचना और परिभाषण मिलेगा **`SERVERPREFmyipc_subsystem`** का, जो मूल रूप से प्राप्त संदेश आईडी पर कॉल करने के लिए फ़ंक्शन को परिभाषित करता है (हमने 500 की शुरुआती संख्या दी है):
|
|
```c
|
|
/* Description of this subsystem, for use in direct RPC */
|
|
const struct SERVERPREFmyipc_subsystem SERVERPREFmyipc_subsystem = {
|
|
myipc_server_routine,
|
|
500, // start ID
|
|
501, // end ID
|
|
(mach_msg_size_t)sizeof(union __ReplyUnion__SERVERPREFmyipc_subsystem),
|
|
(vm_address_t)0,
|
|
{
|
|
{ (mig_impl_routine_t) 0,
|
|
// Function to call
|
|
(mig_stub_routine_t) _XSubtract, 3, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__Subtract_t)},
|
|
}
|
|
};
|
|
```
|
|
{% endtab %}
|
|
|
|
{% tab title="myipcServer.h" %}हम एक नया फ़ाइल myipcServer.h बनाएंगे जिसमें हम अपने IPC सर्वर को परिभाषित करेंगे। यहाँ हमने एक नया मेथड `startMyIPCServer` जोड़ा है जो IPC सर्वर को शुरू करेगा। इसके लिए हमने एक नया विशेष IPC पोर्ट `MY_IPC_PORT` परिभाषित किया है। इसके बाद हमने IPC सर्वर को इस पोर्ट पर बाइंड करने के लिए कुछ और फ़ंक्शन जोड़े हैं। %}
|
|
```c
|
|
/* Description of this subsystem, for use in direct RPC */
|
|
extern const struct SERVERPREFmyipc_subsystem {
|
|
mig_server_routine_t server; /* Server routine */
|
|
mach_msg_id_t start; /* Min routine number */
|
|
mach_msg_id_t end; /* Max routine number + 1 */
|
|
unsigned int maxsize; /* Max msg size */
|
|
vm_address_t reserved; /* Reserved */
|
|
struct routine_descriptor /* Array of routine descriptors */
|
|
routine[1];
|
|
} SERVERPREFmyipc_subsystem;
|
|
```
|
|
{% endtab %}
|
|
{% endtabs %}
|
|
|
|
पिछले स्ट्रक्टर के आधार पर **`myipc_server_routine`** फ़ंक्शन **मैसेज आईडी** प्राप्त करेगा और सही फ़ंक्शन को कॉल करने के लिए लौटेगा:
|
|
```c
|
|
mig_external mig_routine_t myipc_server_routine
|
|
(mach_msg_header_t *InHeadP)
|
|
{
|
|
int msgh_id;
|
|
|
|
msgh_id = InHeadP->msgh_id - 500;
|
|
|
|
if ((msgh_id > 0) || (msgh_id < 0))
|
|
return 0;
|
|
|
|
return SERVERPREFmyipc_subsystem.routine[msgh_id].stub_routine;
|
|
}
|
|
```
|
|
इस उदाहरण में हमने परिभाषणों में केवल 1 फ़ंक्शन परिभाषित किया है, लेकिन अगर हम अधिक फ़ंक्शन परिभाषित करते, तो वे **`SERVERPREFmyipc_subsystem`** के एरे के अंदर होते और पहला फ़ंक्शन **500** आईडी को असाइन किया जाता, दूसरा **501** आईडी को...
|
|
|
|
वास्तव में इस संरचना में इस संबंध को पहचानना संभव है **`myipcServer.h`** से **`subsystem_to_name_map_myipc`** में:
|
|
```c
|
|
#ifndef subsystem_to_name_map_myipc
|
|
#define subsystem_to_name_map_myipc \
|
|
{ "Subtract", 500 }
|
|
#endif
|
|
```
|
|
अंत में, सर्वर काम करने के लिए एक और महत्वपूर्ण फ़ंक्शन **`myipc_server`** होगा, जो वास्तव में **प्राप्त आईडी** के संबंधित फ़ंक्शन को **कॉल** करेगा:
|
|
|
|
<pre class="language-c"><code class="lang-c">mig_external boolean_t myipc_server
|
|
(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
|
|
{
|
|
/*
|
|
* typedef struct {
|
|
* mach_msg_header_t Head;
|
|
* NDR_record_t NDR;
|
|
* kern_return_t RetCode;
|
|
* } mig_reply_error_t;
|
|
*/
|
|
|
|
mig_routine_t routine;
|
|
|
|
OutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);
|
|
OutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;
|
|
/* Minimal size: routine() will update it if different */
|
|
OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
|
|
OutHeadP->msgh_local_port = MACH_PORT_NULL;
|
|
OutHeadP->msgh_id = InHeadP->msgh_id + 100;
|
|
OutHeadP->msgh_reserved = 0;
|
|
|
|
if ((InHeadP->msgh_id > 500) || (InHeadP->msgh_id < 500) ||
|
|
<strong> ((routine = SERVERPREFmyipc_subsystem.routine[InHeadP->msgh_id - 500].stub_routine) == 0)) {
|
|
</strong> ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
|
|
((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
|
|
return FALSE;
|
|
}
|
|
<strong> (*routine) (InHeadP, OutHeadP);
|
|
</strong> return TRUE;
|
|
}
|
|
</code></pre>
|
|
|
|
पिछले हाइलाइट किए गए लाइनों की जांच करें जो आईडी द्वारा कॉल करने के लिए फ़ंक्शन तक पहुंचती हैं।
|
|
|
|
निम्नलिखित में एक सरल **सर्वर** और **क्लाइंट** बनाने के लिए कोड है जहां क्लाइंट सर्वर से फ़ंक्शन Subtract को कॉल कर सकता है:
|
|
|
|
{% tabs %}
|
|
{% tab title="myipc_server.c" %}
|
|
```c
|
|
// gcc myipc_server.c myipcServer.c -o myipc_server
|
|
|
|
#include <stdio.h>
|
|
#include <mach/mach.h>
|
|
#include <servers/bootstrap.h>
|
|
#include "myipcServer.h"
|
|
|
|
kern_return_t SERVERPREFSubtract(mach_port_t server_port, uint32_t n1, uint32_t n2)
|
|
{
|
|
printf("Received: %d - %d = %d\n", n1, n2, n1 - n2);
|
|
return KERN_SUCCESS;
|
|
}
|
|
|
|
int main() {
|
|
|
|
mach_port_t port;
|
|
kern_return_t kr;
|
|
|
|
// Register the mach service
|
|
kr = bootstrap_check_in(bootstrap_port, "xyz.hacktricks.mig", &port);
|
|
if (kr != KERN_SUCCESS) {
|
|
printf("bootstrap_check_in() failed with code 0x%x\n", kr);
|
|
return 1;
|
|
}
|
|
|
|
// myipc_server is the function that handles incoming messages (check previous exlpanation)
|
|
mach_msg_server(myipc_server, sizeof(union __RequestUnion__SERVERPREFmyipc_subsystem), port, MACH_MSG_TIMEOUT_NONE);
|
|
}
|
|
```
|
|
{% endtab %}
|
|
|
|
{% tab title="myipc_client.c" %}हमारे एपीसी क्लाइंट कोड को देखें।{% endtab %}
|
|
```c
|
|
// gcc myipc_client.c myipcUser.c -o myipc_client
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include <mach/mach.h>
|
|
#include <servers/bootstrap.h>
|
|
#include "myipcUser.h"
|
|
|
|
int main() {
|
|
|
|
// Lookup the receiver port using the bootstrap server.
|
|
mach_port_t port;
|
|
kern_return_t kr = bootstrap_look_up(bootstrap_port, "xyz.hacktricks.mig", &port);
|
|
if (kr != KERN_SUCCESS) {
|
|
printf("bootstrap_look_up() failed with code 0x%x\n", kr);
|
|
return 1;
|
|
}
|
|
printf("Port right name %d\n", port);
|
|
USERPREFSubtract(port, 40, 2);
|
|
}
|
|
```
|
|
### बाइनरी विश्लेषण
|
|
|
|
अब बहुत से बाइनरी MIG का उपयोग करते हैं मश पोर्ट्स को उजागर करने के लिए, इसे पहचानना और प्रत्येक संदेश आईडी के साथ MIG द्वारा कार्यान्वित किए जाने वाले **कार्यों को पहचानना** दिलचस्प है।
|
|
|
|
[**jtool2**](../../macos-apps-inspecting-debugging-and-fuzzing/#jtool2) एक Mach-O बाइनरी से MIG सूचना का विश्लेषण कर सकता है जिससे संदेश आईडी को निर्दिष्ट करता है और कार्य को क्रियान्वित करने के लिए पहचानता है:
|
|
```bash
|
|
jtool2 -d __DATA.__const myipc_server | grep MIG
|
|
```
|
|
पहले उल्लेख किया गया था कि **प्राप्त संदेश आईडी के आधार पर सही फ़ंक्शन को बुलाने की जिम्मेदारी लेने वाला फ़ंक्शन** `myipc_server` था। हालांकि, आम तौर पर बाइनरी के प्रतीक नहीं होते (कोई फ़ंक्शन नाम नहीं), इसलिए यह देकने में दिलचस्प है कि **डीकंपाइल करने पर कैसा दिखता है** क्योंकि यह हमेशा बहुत समान होगा (इस फ़ंक्शन का कोड फ़ंक्शनों से अलग होता है):
|
|
|
|
{% tabs %}
|
|
{% tab title="myipc_server decompiled 1" %}
|
|
<pre class="language-c"><code class="lang-c">int _myipc_server(int arg0, int arg1) {
|
|
var_10 = arg0;
|
|
var_18 = arg1;
|
|
// सही फ़ंक्शन पॉइंटर्स पाने के लिए प्रारंभिक निर्देश
|
|
*(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f;
|
|
*(int32_t *)(var_18 + 0x8) = *(int32_t *)(var_10 + 0x8);
|
|
*(int32_t *)(var_18 + 0x4) = 0x24;
|
|
*(int32_t *)(var_18 + 0xc) = 0x0;
|
|
*(int32_t *)(var_18 + 0x14) = *(int32_t *)(var_10 + 0x14) + 0x64;
|
|
*(int32_t *)(var_18 + 0x10) = 0x0;
|
|
if (*(int32_t *)(var_10 + 0x14) <= 0x1f4 && *(int32_t *)(var_10 + 0x14) >= 0x1f4) {
|
|
rax = *(int32_t *)(var_10 + 0x14);
|
|
// इस फ़ंक्शन को पहचानने में मदद करने वाले sign_extend_64 को कॉल करने के लिए
|
|
// यह rax में उस कॉल का पॉइंटर स्टोर करता है जिसे कॉल किया जाना चाहिए
|
|
// पता करें कि पता 0x100004040 (फ़ंक्शन पतों का एरे) का उपयोग किया गया है
|
|
// 0x1f4 = 500 (प्रारंभिक आईडी)
|
|
<strong> rax = *(sign_extend_64(rax - 0x1f4) * 0x28 + 0x100004040);
|
|
</strong> var_20 = rax;
|
|
// अगर - अन्यथा, अगर गलत लौटता है, जबकि अन्यथा सही फ़ंक्शन को कॉल करता है और सही लौटता है
|
|
<strong> if (rax == 0x0) {
|
|
</strong> *(var_18 + 0x18) = **_NDR_record;
|
|
*(int32_t *)(var_18 + 0x20) = 0xfffffffffffffed1;
|
|
var_4 = 0x0;
|
|
}
|
|
else {
|
|
// 2 तर्कों के साथ सही फ़ंक्शन को कॉल करने वाला गणना किया गया पता
|
|
<strong> (var_20)(var_10, var_18);
|
|
</strong> var_4 = 0x1;
|
|
}
|
|
}
|
|
else {
|
|
*(var_18 + 0x18) = **_NDR_record;
|
|
*(int32_t *)(var_18 + 0x20) = 0xfffffffffffffed1;
|
|
var_4 = 0x0;
|
|
}
|
|
rax = var_4;
|
|
return rax;
|
|
}
|
|
</code></pre>
|
|
{% endtab %}
|
|
|
|
{% tab title="myipc_server decompiled 2" %}
|
|
यह एक अलग Hopper मुफ्त संस्करण में डीकंपाइल किया गया समान फ़ंक्शन है:
|
|
|
|
<pre class="language-c"><code class="lang-c">int _myipc_server(int arg0, int arg1) {
|
|
r31 = r31 - 0x40;
|
|
saved_fp = r29;
|
|
stack[-8] = r30;
|
|
var_10 = arg0;
|
|
var_18 = arg1;
|
|
// सही फ़ंक्शन पॉइंटर्स पाने के लिए प्रारंभिक निर्देश
|
|
*(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f | 0x0;
|
|
*(int32_t *)(var_18 + 0x8) = *(int32_t *)(var_10 + 0x8);
|
|
*(int32_t *)(var_18 + 0x4) = 0x24;
|
|
*(int32_t *)(var_18 + 0xc) = 0x0;
|
|
*(int32_t *)(var_18 + 0x14) = *(int32_t *)(var_10 + 0x14) + 0x64;
|
|
*(int32_t *)(var_18 + 0x10) = 0x0;
|
|
r8 = *(int32_t *)(var_10 + 0x14);
|
|
r8 = r8 - 0x1f4;
|
|
if (r8 > 0x0) {
|
|
if (CPU_FLAGS & G) {
|
|
r8 = 0x1;
|
|
}
|
|
}
|
|
if ((r8 & 0x1) == 0x0) {
|
|
r8 = *(int32_t *)(var_10 + 0x14);
|
|
r8 = r8 - 0x1f4;
|
|
if (r8 < 0x0) {
|
|
if (CPU_FLAGS & L) {
|
|
r8 = 0x1;
|
|
}
|
|
}
|
|
if ((r8 & 0x1) == 0x0) {
|
|
r8 = *(int32_t *)(var_10 + 0x14);
|
|
// 0x1f4 = 500 (प्रारंभिक आईडी)
|
|
<strong> r8 = r8 - 0x1f4;
|
|
</strong> asm { smaddl x8, w8, w9, x10 };
|
|
r8 = *(r8 + 0x8);
|
|
var_20 = r8;
|
|
r8 = r8 - 0x0;
|
|
if (r8 != 0x0) {
|
|
if (CPU_FLAGS & NE) {
|
|
r8 = 0x1;
|
|
}
|
|
}
|
|
// पिछले संस्करण की तरह समान अगर नहीं तो अगर गलत लौटता है, जबकि अन्यथा सही फ़ंक्शन को कॉल करता है और सही लौटता है
|
|
<strong> if ((r8 & 0x1) == 0x0) {
|
|
</strong><strong> *(var_18 + 0x18) = **0x100004000;
|
|
</strong> *(int32_t *)(var_18 + 0x20) = 0xfffffed1;
|
|
var_4 = 0x0;
|
|
}
|
|
else {
|
|
// फ़ंक्शन होना चाहिए उस पते पर कॉल करने के लिए गणना का कॉल
|
|
<strong> (var_20)(var_10, var_18);
|
|
</strong> var_4 = 0x1;
|
|
}
|
|
}
|
|
else {
|
|
*(var_18 + 0x18) = **0x100004000;
|
|
*(int32_t *)(var_18 + 0x20) = 0xfffffed1;
|
|
var_4 = 0x0;
|
|
}
|
|
}
|
|
else {
|
|
*(var_18 + 0x18) = **0x100004000;
|
|
*(int32_t *)(var_18 + 0x20) = 0xfffffed1;
|
|
var_4 = 0x0;
|
|
}
|
|
r0 = var_4;
|
|
return r0;
|
|
}
|
|
|
|
</code></pre>
|
|
{% endtab %}
|
|
{% endtabs %}
|
|
|
|
वास्तव में अगर आप **`0x100004000`** फ़ंक्शन पर जाते हैं तो आपको **`routine_descriptor`** संरचनाओं का एरे मिलेगा। संरचना का पहला तत्व वहाँ **फ़ंक्शन** का कार्यान्वयन किया गया है, और **संरचना 0x28 बाइट लेती है**, इसलिए प्रत्येक 0x28 बाइट (बाइट 0 से प्रारंभ करके) आप 8 बाइट प्राप्त कर सकते हैं और वह **फ़ंक्शन का पता** होगा जो कॉल किया जाएगा:
|
|
* **शामिल हों** 💬 [**डिस्कॉर्ड समूह**](https://discord.gg/hRep4RUj7f) या [**टेलीग्राम समूह**](https://t.me/peass) या हमें **ट्विटर** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)** पर **फॉलो** करें।**
|
|
* **अपने हैकिंग ट्रिक्स साझा करें और PR जमा करें** [**HackTricks**](https://github.com/carlospolop/hacktricks) और [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|