mirror of
https://github.com/Karmaz95/Snake_Apple.git
synced 2026-04-11 14:52:03 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61116a35ef | ||
|
|
367c1f3e21 | ||
|
|
ada7094c2b | ||
|
|
3854f0f1b0 |
11
IV. Dylibs/custom/lib1.c
Normal file
11
IV. Dylibs/custom/lib1.c
Normal file
@@ -0,0 +1,11 @@
|
||||
//clang -dynamiclib lib1.c -o $PWD/lib1.dylib -L. -l2
|
||||
#include <stdio.h>
|
||||
#include "lib1.h"
|
||||
#include "lib2.h"
|
||||
|
||||
void callLib1Function() {
|
||||
printf("Now, wer are in lib1.dylib code.\n");
|
||||
printf("Press enter to enter lib2.dylib function\n");
|
||||
getchar();
|
||||
callLib2Function();
|
||||
}
|
||||
7
IV. Dylibs/custom/lib1.h
Normal file
7
IV. Dylibs/custom/lib1.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef LIB1_H
|
||||
#define LIB1_H
|
||||
|
||||
void callLib1Function();
|
||||
|
||||
#endif
|
||||
|
||||
10
IV. Dylibs/custom/lib2.c
Normal file
10
IV. Dylibs/custom/lib2.c
Normal file
@@ -0,0 +1,10 @@
|
||||
//clang -dynamiclib lib2.c -o $PWD/lib2.dylib
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void callLib2Function() {
|
||||
printf("Now we are in lib2.dylib.\n");
|
||||
printf("Press enter to back to executable code...\n");
|
||||
getchar();
|
||||
}
|
||||
7
IV. Dylibs/custom/lib2.h
Normal file
7
IV. Dylibs/custom/lib2.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef LIB2_H
|
||||
#define LIB2_H
|
||||
|
||||
void callLib2Function();
|
||||
|
||||
#endif
|
||||
|
||||
17
IV. Dylibs/custom/m.c
Normal file
17
IV. Dylibs/custom/m.c
Normal file
@@ -0,0 +1,17 @@
|
||||
// clang -dynamiclib m.c -o m.dylib //-o $PWD/TARGET_DYLIB
|
||||
#include <syslog.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
__attribute__((constructor))
|
||||
void myconstructor(int argc, const char **argv)
|
||||
{
|
||||
syslog(LOG_ERR, "[+] m.dylib injected in %s\n", argv[0]);
|
||||
printf("[+] m.dylib injected in %s\n", argv[0]);
|
||||
setuid(0);
|
||||
system("id");
|
||||
//system("/bin/sh");
|
||||
}
|
||||
|
||||
void callLib1Function(void){}
|
||||
15
IV. Dylibs/custom/main.c
Normal file
15
IV. Dylibs/custom/main.c
Normal file
@@ -0,0 +1,15 @@
|
||||
//clang main.c -o $PWD/executable -L. -l1
|
||||
//codesign -s IDENTITY --option=runtime -f executable
|
||||
#include <stdio.h>
|
||||
#include "lib1.h"
|
||||
|
||||
int main() {
|
||||
printf("Main program\n");
|
||||
printf("Press enter to call lib1.dylib function...\n");
|
||||
getchar();
|
||||
callLib1Function();
|
||||
printf("Press Enter to exit...\n");
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
|
||||
6
IV. Dylibs/custom/mylib.c
Normal file
6
IV. Dylibs/custom/mylib.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "mylib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void myFunction() {
|
||||
printf("Hello from mylib!\n");
|
||||
}
|
||||
1
IV. Dylibs/custom/mylib.h
Normal file
1
IV. Dylibs/custom/mylib.h
Normal file
@@ -0,0 +1 @@
|
||||
void my_function(); // Declare the function prototype
|
||||
6
IV. Dylibs/custom/use_mylib.c
Normal file
6
IV. Dylibs/custom/use_mylib.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "mylib.h"
|
||||
|
||||
int main() {
|
||||
myFunction(); // Call the function from the library
|
||||
return 0;
|
||||
}
|
||||
2537
IV. Dylibs/macos/Header.cpp
Normal file
2537
IV. Dylibs/macos/Header.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1966
IV. Dylibs/macos/ImageLoader.cpp
Normal file
1966
IV. Dylibs/macos/ImageLoader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3250
IV. Dylibs/macos/Loader.cpp
Normal file
3250
IV. Dylibs/macos/Loader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4094
IV. Dylibs/macos/MachOFile.cpp
Normal file
4094
IV. Dylibs/macos/MachOFile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1590
IV. Dylibs/macos/loader.h
Normal file
1590
IV. Dylibs/macos/loader.h
Normal file
File diff suppressed because it is too large
Load Diff
1304
IV. Dylibs/python/CrimsonUroboros.py
Executable file
1304
IV. Dylibs/python/CrimsonUroboros.py
Executable file
File diff suppressed because it is too large
Load Diff
100
IV. Dylibs/python/MachODylibLoadCommandsFinder.py
Normal file
100
IV. Dylibs/python/MachODylibLoadCommandsFinder.py
Normal file
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import lief
|
||||
|
||||
|
||||
class MachODylibLoadCommandsFinder:
|
||||
'''
|
||||
Recursively crawl the system and parse Mach-O files to find DYLIB related load commands.
|
||||
1. Check if the file is a Mach-O.
|
||||
2. List all Load Commands.
|
||||
3. Check if any DYLIB-related LC exists.
|
||||
LC_LOAD_DYLIB
|
||||
LC_ID_DYLIB
|
||||
LC_PREBOUND_DYLIB
|
||||
LC_LOAD_WEAK_DYLIB
|
||||
LC_REEXPORT_DYLIB
|
||||
LC_LAZY_LOAD_DYLIB
|
||||
LC_LOAD_UPWARD_DYLIB
|
||||
LC_RPATH
|
||||
4. Print the total Mach-O files analyzed and how many DYLIB-related LCs existed.
|
||||
'''
|
||||
def __init__(self):
|
||||
self.total_files_analyzed = 0
|
||||
self.binary_dylibs = {}
|
||||
self.dylib_counts = {
|
||||
"LC_LOAD_DYLIB" : 0,
|
||||
"LC_ID_DYLIB": 0,
|
||||
"LC_PREBOUND_DYLIB": 0,
|
||||
"LC_LOAD_WEAK_DYLIB": 0,
|
||||
"LC_REEXPORT_DYLIB": 0,
|
||||
"LC_LAZY_LOAD_DYLIB": 0,
|
||||
"LC_LOAD_UPWARD_DYLIB": 0,
|
||||
"LC_RPATH": 0,
|
||||
}
|
||||
|
||||
def parseDirectory(self, directory_path):
|
||||
'''Recursively check if the path is a file. If it is, use checkIfMacho method.'''
|
||||
for root, dirs, files in os.walk(directory_path):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
if os.path.isfile(file_path):
|
||||
self.checkIfMacho(file_path)
|
||||
|
||||
def checkIfMacho(self, file_path):
|
||||
binaries = lief.MachO.parse(file_path)
|
||||
if binaries:
|
||||
self.parseFatBinary(binaries, file_path)
|
||||
|
||||
def parseFatBinary(self, binaries, file_path):
|
||||
for binary in binaries:
|
||||
if binary.header.cpu_type == lief.MachO.CPU_TYPES.ARM64:
|
||||
self.total_files_analyzed += 1
|
||||
self.checkDylibLoadCommands(binary, file_path)
|
||||
|
||||
def checkDylibLoadCommands(self, binary, file_path):
|
||||
dylib_related_lcs = {
|
||||
lief.MachO.LOAD_COMMAND_TYPES.LOAD_DYLIB: "LC_LOAD_DYLIB",
|
||||
lief.MachO.LOAD_COMMAND_TYPES.ID_DYLIB: "LC_ID_DYLIB",
|
||||
lief.MachO.LOAD_COMMAND_TYPES.PREBOUND_DYLIB: "LC_PREBOUND_DYLIB",
|
||||
lief.MachO.LOAD_COMMAND_TYPES.LOAD_WEAK_DYLIB: "LC_LOAD_WEAK_DYLIB",
|
||||
lief.MachO.LOAD_COMMAND_TYPES.REEXPORT_DYLIB: "LC_REEXPORT_DYLIB",
|
||||
lief.MachO.LOAD_COMMAND_TYPES.LAZY_LOAD_DYLIB: "LC_LAZY_LOAD_DYLIB",
|
||||
lief.MachO.LOAD_COMMAND_TYPES.LOAD_UPWARD_DYLIB: "LC_LOAD_UPWARD_DYLIB",
|
||||
lief.MachO.LOAD_COMMAND_TYPES.RPATH: "LC_RPATH",
|
||||
}
|
||||
|
||||
binary_dylibs_set = set()
|
||||
|
||||
for cmd in binary.commands:
|
||||
if cmd.command in dylib_related_lcs:
|
||||
lc_name = dylib_related_lcs[cmd.command]
|
||||
self.dylib_counts[lc_name] += 1
|
||||
binary_dylibs_set.add(lc_name)
|
||||
|
||||
self.binary_dylibs[file_path] = binary_dylibs_set
|
||||
|
||||
def print_results(self):
|
||||
print(f"Total Mach-O files analyzed: {self.total_files_analyzed}")
|
||||
print("DYLIB-related LC counts:")
|
||||
for lc, count in self.dylib_counts.items():
|
||||
print(f"{lc}: {count}")
|
||||
|
||||
print("\nBinary Dylibs:")
|
||||
for binary, dylibs in self.binary_dylibs.items():
|
||||
print(f"{binary}: {dylibs}")
|
||||
|
||||
def save_results(self):
|
||||
with open("MachODylibLoadCommandsFinder_results.txt", "a") as f:
|
||||
f.write(f"Total Mach-O files analyzed: {self.total_files_analyzed}\n")
|
||||
f.write("DYLIB-related LC counts:\n")
|
||||
for lc, count in self.dylib_counts.items():
|
||||
f.write(f"{lc}: {count}\n")
|
||||
for binary, dylibs in self.binary_dylibs.items():
|
||||
f.write(f"{binary}: {', '.join(dylibs)}\n")
|
||||
|
||||
|
||||
macho_checker = MachODylibLoadCommandsFinder()
|
||||
macho_checker.parseDirectory("/")
|
||||
macho_checker.print_results()
|
||||
macho_checker.save_results()
|
||||
129
README.md
129
README.md
@@ -1,4 +1,5 @@
|
||||
# Snake & Apple
|
||||

|
||||
The code repository for the `Snake&Apple` article series, which documents my research about macOS security.
|
||||
|
||||
Each article directory contains three subdirectories:
|
||||
@@ -7,29 +8,33 @@ Each article directory contains three subdirectories:
|
||||
* `python` - contains the latest CrimsonUroboros and other Python scripts created during research.
|
||||
|
||||
## ARTICLES
|
||||

|
||||
|
||||
* ☑ [I. Mach-O](https://karol-mazurek95.medium.com/snake-apple-i-mach-o-a8eda4b87263?sk=v2%2Ffc1cbfa4-e2d4-4387-9a82-b27191978b5b)
|
||||
* ☑ [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]()
|
||||
* ☑ [IV. Dylibs](https://karol-mazurek.medium.com/snake-apple-iv-dylibs-2c955439b94e?sk=v2%2Fdef72b7a-121a-47a1-af89-7bf53aed1ea2)
|
||||
|
||||
## TOOLS
|
||||
### [CrimsonUroboros](III.%20Checksec/python/CrimsonUroboros.py)
|
||||
[CrimsonUroboros](#crimsonuroboros) • [MachOFileFinder](#machofilefinder) • [TrustCacheParser](#trustcacheparser) • [SignatureReader](#signaturereader) • [extract_cms.sh](#extract_cmssh) • [ModifyMachOFlags](#modifymachoflags) • [LCFinder](#lcfinder)
|
||||
***
|
||||
|
||||
### [CrimsonUroboros](IV.%20Dylibs/python/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] [--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]]
|
||||
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]]
|
||||
|
||||
Mach-O files parser for binary analysis
|
||||
|
||||
@@ -50,36 +55,77 @@ MACH-O ARGS:
|
||||
--exports_trie Print Export Trie information
|
||||
--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)
|
||||
--strings_section Print strings from __cstring section
|
||||
--all_strings Print strings from all sections
|
||||
--save_strings all_strings.txt
|
||||
Parse all sections, detect strings, and save them to a
|
||||
file
|
||||
--info Print header, load commands, segments, sections,
|
||||
symbols, and strings
|
||||
Parse all sections, detect strings, and save them to a file
|
||||
--info Print header, load commands, segments, sections, symbols, and strings
|
||||
|
||||
CODE SIGNING ARGS:
|
||||
--verify_signature Code Signature verification (if the contents of the
|
||||
binary have been modified)
|
||||
--verify_signature Code Signature verification (if the contents of the binary have been modified)
|
||||
--cd_info Print Code Signature information
|
||||
--cd_requirements Print Code Signature Requirements
|
||||
--entitlements [human|xml|var]
|
||||
Print Entitlements in a human-readable, XML, or DER
|
||||
format (default: human)
|
||||
Print Entitlements in a human-readable, XML, or DER format (default: human)
|
||||
--extract_cms cms_signature.der
|
||||
Extract CMS Signature from the Code Signature and save
|
||||
it to a given file
|
||||
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
|
||||
--has_arc Check if Automatic Reference Counting (ARC) is in use (can be false positive)
|
||||
--is_stripped Check if binary is stripped
|
||||
--has_canary Check if Stack Canary is in use (can be false positive)
|
||||
--has_nx_stack Check if stack is non-executable (NX stack)
|
||||
--has_nx_heap Check if heap is non-executable (NX heap)
|
||||
--has_xn Check if binary is protected by eXecute Never (XN) ARM protection
|
||||
--is_notarized Check if the application is notarized and can pass the Gatekeeper verification
|
||||
--is_encrypted Check if the application is encrypted (has LC_ENCRYPTION_INFO(_64) and cryptid set to 1)
|
||||
--has_restrict Check if binary has __RESTRICT segment
|
||||
--is_hr Check if the Hardened Runtime is in use
|
||||
--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
|
||||
--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)
|
||||
--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_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)
|
||||
--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
|
||||
--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
|
||||
--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
|
||||
```
|
||||
* Example:
|
||||
```bash
|
||||
@@ -212,17 +258,29 @@ LCFinder -l macho_paths.txt --lc SEGMENT_64 2>/dev/null
|
||||
LCFinder -p hello --lc lc_segment_64 2>/dev/null
|
||||
```
|
||||
***
|
||||
### [MachODylibLoadCommandsFinder](IV.%20Dylibs/python/MachODylibLoadCommandsFinder.py)
|
||||
Designed to Recursively crawl the system and parse Mach-O files to find DYLIB related load commands.
|
||||
Print the total Mach-O files analyzed and how many DYLIB-related LCs existed
|
||||
* Usage:
|
||||
```console
|
||||
MachODylibLoadCommandsFinder 2>/dev/null
|
||||
```
|
||||
|
||||
## INSTALL
|
||||
```
|
||||
pip -r requirements.txt
|
||||
python3 -m pip install pyimg4
|
||||
wget https://github.com/CRKatri/trustcache/releases/download/v2.0/trustcache_macos_arm64 -O /usr/local/bin/trustcache
|
||||
chmod +x /usr/local/bin/trustcache
|
||||
xattr -d com.apple.quarantine /usr/local/bin/trustcache
|
||||
brew install keith/formulae/dyld-shared-cache-extractor
|
||||
brew install blacktop/tap/ipsw
|
||||
```
|
||||
|
||||
## LIMITATIONS
|
||||
* Codesigning module(codesign wrapper) works only on macOS.
|
||||
* `--dylib_hijacking` needs [ipsw](https://github.com/blacktop/ipsw) to be installed.
|
||||
* `--dylibtree` needs the [dyld-shared-cache-extractor](https://github.com/keith/dyld-shared-cache-extractor) to be installed.
|
||||
|
||||
|
||||
## WHY UROBOROS?
|
||||
I will write the code for each article as a class SnakeX, where X will be the article number. To make it easier for the audience to follow. Each Snake class will be a child of the previous one and infinitely "eat itself" (inherit methods of the previous class), like Uroboros.
|
||||
@@ -232,9 +290,12 @@ I will write the code for each article as a class SnakeX, where X will be the ar
|
||||
* [XNU](https://github.com/apple-oss-distributions/xnu)
|
||||
* [dyld](https://github.com/apple-oss-distributions/dyld)
|
||||
|
||||
## TODO
|
||||
## TODO - IDEAS / IMPROVES
|
||||
* DER Entitlements converter method - currently, only the `convert_xml_entitlements_to_dict()` method exists. I need to create a Python parser for DER-encoded entitlements.
|
||||
* SuperBlob parser - to find other blobs in Code Signature.
|
||||
* Entitlements Blob parser - to check if XML and DER blobs exist.
|
||||
* 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.
|
||||
* 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`
|
||||
Reference in New Issue
Block a user