mirror of
https://github.com/Karmaz95/Snake_Apple.git
synced 2026-03-30 14:00:16 +02:00
This commit is contained in:
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,2 +1,11 @@
|
||||
# Exclude .DS_Store files
|
||||
**/.DS_Store
|
||||
**/.vscode
|
||||
|
||||
# Exclude .vscode directory
|
||||
**/.vscode/
|
||||
|
||||
# Exclude __pycache__ directories
|
||||
__pycache__/
|
||||
|
||||
# Exclude pytest_cache directories
|
||||
.pytest_cache/
|
||||
File diff suppressed because it is too large
Load Diff
72
README.md
72
README.md
@@ -13,28 +13,27 @@ Each article directory contains three subdirectories:
|
||||
* ☑ [II. Code Signing](https://karol-mazurek95.medium.com/snake-apple-ii-code-signing-f0a9967b7f02?sk=v2%2Fbbc87007-89ca-4135-91d6-668b5d2fe9ae)
|
||||
* ☑ [III. Checksec](https://karol-mazurek95.medium.com/snake-apple-iii-checksec-ed64a4b766c1?sk=v2%2Fb4b8d637-e906-4b6b-8088-ca1f893cd787)
|
||||
* ☑ [IV. Dylibs](https://karol-mazurek.medium.com/snake-apple-iv-dylibs-2c955439b94e?sk=v2%2Fdef72b7a-121a-47a1-af89-7bf53aed1ea2)
|
||||
* ☐ [V. Dyld]()
|
||||
* ☑ [DYLD — Do You Like Death? (I)](https://karol-mazurek.medium.com/dyld-do-you-like-death-i-8199faad040e?sk=v2%2F359b081f-d944-409b-9e7c-95f7c171b969)
|
||||
* ☐ [DYLD — Do You Like Death? (II)]()
|
||||
|
||||
## TOOLS
|
||||
[CrimsonUroboros](#crimsonuroboros) • [MachOFileFinder](#machofilefinder) • [TrustCacheParser](#trustcacheparser) • [SignatureReader](#signaturereader) • [extract_cms.sh](#extract_cmssh) • [ModifyMachOFlags](#modifymachoflags) • [LCFinder](#lcfinder)
|
||||
[CrimsonUroboros](#crimsonuroboros) • [MachOFileFinder](#machofilefinder) • [TrustCacheParser](#trustcacheparser) • [SignatureReader](#signaturereader) • [extract_cms.sh](#extract_cmssh) • [ModifyMachOFlags](#modifymachoflags) • [LCFinder](#lcfinder) • [MachODylibLoadCommandsFinder](#machodylibloadcommandsfinder)
|
||||
***
|
||||
|
||||
### [CrimsonUroboros](IV.%20Dylibs/python/CrimsonUroboros.py)
|
||||
### [CrimsonUroboros](tests/CrimsonUroboros.py)
|
||||

|
||||
Core program resulting from the Snake&Apple article series for binary analysis. You may find older versions of this script in each article directory in this repository.
|
||||
* Usage
|
||||
```console
|
||||
usage: CrimsonUroboros [-h] -p PATH [--file_type] [--header_flags] [--endian] [--header] [--load_commands] [--segments]
|
||||
[--sections] [--symbols] [--chained_fixups] [--exports_trie] [--uuid] [--main]
|
||||
[--encryption_info [(optional) save_path.bytes]] [--strings_section] [--all_strings]
|
||||
[--save_strings all_strings.txt] [--info] [--verify_signature] [--cd_info] [--cd_requirements]
|
||||
[--entitlements [human|xml|var]] [--extract_cms cms_signature.der]
|
||||
[--extract_certificates certificate_name] [--remove_sig unsigned_binary]
|
||||
[--sign_binary [adhoc|identity_number]] [--has_pie] [--has_arc] [--is_stripped] [--has_canary]
|
||||
[--has_nx_stack] [--has_nx_heap] [--has_xn] [--is_notarized] [--is_encrypted] [--has_restrict]
|
||||
[--is_hr] [--is_as] [--is_fort] [--has_rpath] [--checksec] [--dylibs] [--rpaths] [--rpaths_u]
|
||||
[--dylibs_paths] [--dylibs_paths_u] [--broken_relative_paths]
|
||||
[--dylibtree [cache_path,output_path,is_extracted]] [--dylib_id] [--reexport_paths] [--hijack_sec]
|
||||
[--dylib_hijacking [cache_path]] [--prepare_dylib [target_dylib_path]]
|
||||
usage: CrimsonUroboros [-h] -p PATH [--file_type] [--header_flags] [--endian] [--header] [--load_commands] [--segments] [--sections] [--symbols] [--chained_fixups] [--exports_trie]
|
||||
[--uuid] [--main] [--encryption_info [(optional) save_path.bytes]] [--strings_section] [--all_strings] [--save_strings all_strings.txt] [--info]
|
||||
[--verify_signature] [--cd_info] [--cd_requirements] [--entitlements [human|xml|var]] [--extract_cms cms_signature.der]
|
||||
[--extract_certificates certificate_name] [--remove_sig unsigned_binary] [--sign_binary [adhoc|identity_number]] [--has_pie] [--has_arc] [--is_stripped]
|
||||
[--has_canary] [--has_nx_stack] [--has_nx_heap] [--has_xn] [--is_notarized] [--is_encrypted] [--has_restrict] [--is_hr] [--is_as] [--is_fort] [--has_rpath]
|
||||
[--has_lv] [--checksec] [--dylibs] [--rpaths] [--rpaths_u] [--dylibs_paths] [--dylibs_paths_u] [--broken_relative_paths]
|
||||
[--dylibtree [cache_path,output_path,is_extracted]] [--dylib_id] [--reexport_paths] [--hijack_sec] [--dylib_hijacking [cache_path]]
|
||||
[--dylib_hijacking_a [cache_path]] [--prepare_dylib [target_dylib_path]]
|
||||
|
||||
Mach-O files parser for binary analysis
|
||||
|
||||
@@ -56,8 +55,7 @@ MACH-O ARGS:
|
||||
--uuid Print UUID
|
||||
--main Print entry point and stack size
|
||||
--encryption_info [(optional) save_path.bytes]
|
||||
Print encryption info if any. Optionally specify an output path to dump the encrypted data (if
|
||||
cryptid=0, data will be in plain text)
|
||||
Print encryption info if any. Optionally specify an output path to dump the encrypted data (if cryptid=0, data will be in plain text)
|
||||
--strings_section Print strings from __cstring section
|
||||
--all_strings Print strings from all sections
|
||||
--save_strings all_strings.txt
|
||||
@@ -73,13 +71,12 @@ CODE SIGNING ARGS:
|
||||
--extract_cms cms_signature.der
|
||||
Extract CMS Signature from the Code Signature and save it to a given file
|
||||
--extract_certificates certificate_name
|
||||
Extract Certificates and save them to a given file. To each filename will be added an index at
|
||||
the end: _0 for signing, _1 for intermediate, and _2 for root CA certificate
|
||||
Extract Certificates and save them to a given file. To each filename will be added an index at the end: _0 for signing, _1 for intermediate, and _2 for root CA
|
||||
certificate
|
||||
--remove_sig unsigned_binary
|
||||
Save the new file on a disk with removed signature
|
||||
--sign_binary [adhoc|identity_number]
|
||||
Sign binary using specified identity - use : 'security find-identity -v -p codesigning' to get
|
||||
the identity (default: adhoc)
|
||||
Sign binary using specified identity - use : 'security find-identity -v -p codesigning' to get the identity (default: adhoc)
|
||||
|
||||
CHECKSEC ARGS:
|
||||
--has_pie Check if Position-Independent Executable (PIE) is set
|
||||
@@ -96,36 +93,33 @@ CHECKSEC ARGS:
|
||||
--is_as Check if the App Sandbox is in use
|
||||
--is_fort Check if the binary is fortified
|
||||
--has_rpath Check if the binary utilise any @rpath variables
|
||||
--has_lv Check if the binary has Library Validation (protection against Dylib Hijacking)
|
||||
--checksec Run all checksec module options on the binary
|
||||
|
||||
DYLIBS ARGS:
|
||||
--dylibs Print shared libraries used by specified binary with compatibility and the current version
|
||||
(loading paths unresolved, like @rpath/example.dylib)
|
||||
--dylibs Print shared libraries used by specified binary with compatibility and the current version (loading paths unresolved, like @rpath/example.dylib)
|
||||
--rpaths Print all paths (resolved) that @rpath can be resolved to
|
||||
--rpaths_u Print all paths (unresolved) that @rpath can be resolved to
|
||||
--dylibs_paths Print absolute dylib loading paths (resolved @rpath|@executable_path|@loader_path) in order they
|
||||
are searched for
|
||||
--dylibs_paths Print absolute dylib loading paths (resolved @rpath|@executable_path|@loader_path) in order they are searched for
|
||||
--dylibs_paths_u Print unresolved dylib loading paths.
|
||||
--broken_relative_paths
|
||||
Print 'broken' relative paths from the binary (cases where the dylib source is specified for an
|
||||
executable directory without @executable_path)
|
||||
Print 'broken' relative paths from the binary (cases where the dylib source is specified for an executable directory without @executable_path)
|
||||
--dylibtree [cache_path,output_path,is_extracted]
|
||||
Print the dynamic dependencies of a Mach-O binary recursively. You can specify the Dyld Shared
|
||||
Cache path in the first argument, the output directory as the 2nd argument, and if you have
|
||||
already extracted DSC in the 3rd argument (0 or 1). The output_path will be used as a base for
|
||||
dylibtree. For example, to not extract DSC, use: --dylibs ",,1", or to extract from default to
|
||||
default use just --dylibs or --dylibs ",,0" which will extract DSC to extracted_dyld_share_cache/
|
||||
in the current directory
|
||||
Print the dynamic dependencies of a Mach-O binary recursively. You can specify the Dyld Shared Cache path in the first argument, the output directory as the
|
||||
2nd argument, and if you have already extracted DSC in the 3rd argument (0 or 1). The output_path will be used as a base for dylibtree. For example, to not
|
||||
extract DSC, use: --dylibs ",,1", or to extract from default to default use just --dylibs or --dylibs ",,0" which will extract DSC to
|
||||
extracted_dyld_share_cache/ in the current directory
|
||||
--dylib_id Print path from LC_ID_DYLIB
|
||||
--reexport_paths Print paths from LC_REEXPORT_DLIB
|
||||
--hijack_sec Check if binary is protected against Dylib Hijacking
|
||||
--dylib_hijacking [cache_path]
|
||||
Check for possible Direct and Indirect Dylib Hijacking loading paths. (optional) Specify the path
|
||||
to the Dyld Shared Cache
|
||||
Check for possible Direct and Indirect Dylib Hijacking loading paths. The output is printed to console and saved in JSON format to
|
||||
/tmp/dylib_hijacking_log.json(append mode). (optional)Specify the path to the Dyld Shared Cache
|
||||
--dylib_hijacking_a [cache_path]
|
||||
Like --dylib_hijacking, but shows only possible vectors (without protected binaries)
|
||||
--prepare_dylib [target_dylib_path]
|
||||
Compile rogue dylib. (optional) Specify target_dylib_path, it will search for the imported
|
||||
symbols from it in the dylib specified in the --path argument and automatically add it to the
|
||||
source code of the rogue lib. Example: --path lib1.dylib --prepare_dylib /path/to/lib2.dylib
|
||||
Compile rogue dylib. (optional) Specify target_dylib_path, it will search for the imported symbols from it in the dylib specified in the --path argument and
|
||||
automatically add it to the source code of the rogue lib. Example: --path lib1.dylib --prepare_dylib /path/to/lib2.dylib
|
||||
```
|
||||
* Example:
|
||||
```bash
|
||||
@@ -297,5 +291,5 @@ I will write the code for each article as a class SnakeX, where X will be the ar
|
||||
* Every method in the Snake class that use Entitlements should parse first XML > DER (currently, only XML parser exists)
|
||||
* After making a SuperBlob parser and CodeDirectory blob parser, modify hasHardenedRuntime to check Runtime flag by using bitmask, instead of string.
|
||||
* Build Dyld Shared Cache parser and extractor to make SnakeIV independant of dyld-shared-cache-extractor.
|
||||
* Add check for `CS_RESTRICT` (`0x800`) in --`checksec` to `RESTRICTED`
|
||||
* Add check for `DYLIB HIJACKING` to --`checksec`
|
||||
* Make testing branch and implement tests, before pushing new updates.
|
||||
* Create `RottenApple.app` in another repository and use it for testing.
|
||||
63
V. Dyld/custom/lambda_capture_example.cpp
Normal file
63
V. Dyld/custom/lambda_capture_example.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
//g++ -std=c++11 lambda_capture_example.cpp -o lambda_capture_example
|
||||
|
||||
/*
|
||||
This example demonstrates how lambda capture by reference [&] allows the lambda function to access and modify variables from the outer scope directly.
|
||||
|
||||
1. We have a function withWritableMemory that simulates the process of making memory writable, executing some work, and then restoring memory protection.
|
||||
2. In the main function, we have variables x and y.
|
||||
3. We define a lambda function lambda capturing all variables by reference [&]().
|
||||
4. Inside the lambda, we modify the values of x and y.
|
||||
5. We call withWritableMemory and pass the lambda as an argument.
|
||||
6. The lambda is executed within the withWritableMemory function.
|
||||
7. After the lambda execution, we print the values of x and y to see the changes made inside the lambda.
|
||||
*/
|
||||
#include <iostream>
|
||||
|
||||
void withWritableMemory(std::function<void()> work) {
|
||||
std::cout << "Entering withWritableMemory function" << std::endl;
|
||||
// Simulating the setup before making memory writable
|
||||
std::cout << "Setting up memory..." << std::endl;
|
||||
|
||||
// Make memory writable
|
||||
|
||||
// Execute the provided work function
|
||||
work();
|
||||
|
||||
// Restore memory protection
|
||||
std::cout << "Restoring memory protection..." << std::endl;
|
||||
|
||||
std::cout << "Exiting withWritableMemory function" << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int x = 5;
|
||||
int y = 3;
|
||||
|
||||
// Lambda function capturing all variables by reference
|
||||
auto lambda = [&]() {
|
||||
// Access and modify variables from the outer scope
|
||||
x = x + 10;
|
||||
y = y * 2;
|
||||
|
||||
std::cout << "Inside lambda: x = " << x << ", y = " << y << std::endl;
|
||||
};
|
||||
|
||||
// Call the function with the lambda as an argument
|
||||
withWritableMemory(lambda);
|
||||
|
||||
// After the lambda is executed
|
||||
std::cout << "After lambda: x = " << x << ", y = " << y << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
./lambda_capture_example
|
||||
|
||||
Entering withWritableMemory function
|
||||
Setting up memory...
|
||||
Inside lambda: x = 15, y = 6
|
||||
Restoring memory protection...
|
||||
Exiting withWritableMemory function
|
||||
After lambda: x = 15, y = 6
|
||||
*/
|
||||
26
V. Dyld/custom/rosetta_dyld_is_translated_pointer_example.c
Normal file
26
V. Dyld/custom/rosetta_dyld_is_translated_pointer_example.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int rosetta_dyld_is_translated(bool *is_translated);
|
||||
|
||||
// Pseudo implementation of SyscallDelegate::isTranslated
|
||||
bool isTranslated() {
|
||||
bool is_translated = false;
|
||||
if (rosetta_dyld_is_translated(&is_translated) == 0) {
|
||||
return is_translated;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mock implementation of rosetta_dyld_is_translated for demonstration purposes
|
||||
// This function always sets is_translated to true using pointer - for the sake of the example
|
||||
int rosetta_dyld_is_translated(bool *is_translated) {
|
||||
*is_translated = true; // Simulated behavior: always set is_translated to true
|
||||
return 0; // Return success
|
||||
}
|
||||
|
||||
int main() {
|
||||
bool translated = isTranslated();
|
||||
printf("Is translated: %s\n", translated ? "true" : "false");
|
||||
return 0;
|
||||
}
|
||||
1581
V. Dyld/python/CrimsonUroboros.py
Executable file
1581
V. Dyld/python/CrimsonUroboros.py
Executable file
File diff suppressed because it is too large
Load Diff
1
tests/CrimsonUroboros.py
Symbolic link
1
tests/CrimsonUroboros.py
Symbolic link
@@ -0,0 +1 @@
|
||||
../V. Dyld/python/CrimsonUroboros.py
|
||||
81
tests/CrimsonUroborosTester.py
Normal file
81
tests/CrimsonUroborosTester.py
Normal file
@@ -0,0 +1,81 @@
|
||||
import pytest
|
||||
import subprocess
|
||||
from CrimsonUroboros import * # Symlinked to the source file, which is the latest version of the CrimsonUroboros.py file.
|
||||
|
||||
class Compiler:
|
||||
def __init__(self):
|
||||
self.compiled_files = [] # Stores the paths to the compiled files.
|
||||
|
||||
def compile(self, cmd):
|
||||
"""
|
||||
Compile C code using the given compile command.
|
||||
|
||||
Args:
|
||||
cmd (str): The compile command to run.
|
||||
|
||||
Returns:
|
||||
int: Return code of the compilation process.
|
||||
"""
|
||||
result = subprocess.run(cmd, shell=True)
|
||||
return result.returncode
|
||||
|
||||
def buildClangCommand(self, source, output, flags=None):
|
||||
"""
|
||||
Build a clang compile command string based on the source file, output file, and optional flags.
|
||||
|
||||
Args:
|
||||
source (str): Path to the source file.
|
||||
output (str): Path to the output file.
|
||||
flags (list, optional): List of additional flags. Defaults to None.
|
||||
|
||||
Returns:
|
||||
str: Compiled clang command string.
|
||||
"""
|
||||
cmd_parts = ["clang"]
|
||||
cmd_parts.append(source)
|
||||
cmd_parts.extend(["-o", output])
|
||||
if flags:
|
||||
cmd_parts.extend(flags)
|
||||
|
||||
return ' '.join(cmd_parts)
|
||||
|
||||
def compileIt(self, source, output, flags=None):
|
||||
"""
|
||||
Compile the given source file using clang.
|
||||
|
||||
Args:
|
||||
source (str): The path to the source file.
|
||||
output (str): The path to the output file.
|
||||
flags (list, optional): Additional compilation flags. Defaults to None.
|
||||
|
||||
Returns:
|
||||
int: The exit code of the compilation process.
|
||||
"""
|
||||
cmd = self.buildClangCommand(source, output, flags)
|
||||
result = self.compile(cmd)
|
||||
self.compiled_files.append(output)
|
||||
return result
|
||||
|
||||
def purgeCompiledFiles(self):
|
||||
"""
|
||||
Remove all compiled files.
|
||||
"""
|
||||
for file in self.compiled_files:
|
||||
subprocess.run(["rm", file])
|
||||
|
||||
'''# TODO:
|
||||
compiler = Compiler()
|
||||
compiler.compileIt("../I.\ Mach-O/custom/hello.c", "hello")
|
||||
|
||||
print(compiler.compiled_files)
|
||||
|
||||
|
||||
class TestSnakeI:
|
||||
def test_method1(self):
|
||||
''''''
|
||||
# Test_
|
||||
obj = CrimsonUroboros()
|
||||
input_data = 1
|
||||
expected_output = 2
|
||||
assert obj.method1(input_data) == expected_output
|
||||
'''
|
||||
Reference in New Issue
Block a user