Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

everettjf/WasmPatch

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

44 Commits
44 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

WasmPatch ๐Ÿงฑ

GitHub Stars GitHub Forks License Issues

WebAssembly-driven hot patching for iOS/macOS Objective-C apps

English

Hot-fix iOS/macOS apps using WebAssembly payloads. Compile C code to WASM and replace Objective-C methods at runtime.


๐ŸŽฏ What is WasmPatch?

WasmPatch bridges Objective-C and WebAssembly. It compiles C code into WebAssembly modules and lets those modules call any Objective-C class or method dynamically โ€” so you can hot-fix bugs, add features, and replace methods at runtime without shipping a new binary.

Capabilities at a glance

Patch & bridge

  • ๐Ÿ”„ Replace class & instance methods at runtime; call any Obj-C method from wasm
  • ๐Ÿ“ Pass/return structs by value โ€” CGPoint/CGSize/CGRect/NSRange and arbitrary structs via alloc_struct + field accessors
  • ๐Ÿงฉ Blocks both ways โ€” invoke completion handlers you're handed (invoke_block) and create blocks to pass into Obj-C (create_block)
  • ๐Ÿ”ข Value-type bridging for strings, numbers, BOOL, objects, selectors, C strings

Swift support

  • ๐Ÿฆ… Hook @objc dynamic Swift methods; module-qualified class names
  • ๐Ÿ”Ž Tool/scan-hookable.sh lists a binary's hookable surface; clean Swift API via NS_SWIFT_NAME โ€” see SWIFT.md

Authoring & tooling

  • โœ๏ธ WAP_REPLACE_* macros (a misspelled target fails to compile), scope cleanup pools, call_*_3/4
  • ๐Ÿ› ๏ธ Tool/wasmpatch CLI โ€” doctor, build (auto-injects <wasmpatch.h>, emits sha256/meta), keygen, sign
  • ๐Ÿ“ฆ Integrates via Swift Package Manager and CocoaPods

Delivery & safety

  • ๐ŸŒ WAPPatchManager โ€” fetch, verify, cache, and apply remote patches
  • ๐Ÿ” EC P-256 signature verification (authenticity) on top of SHA-256 (integrity)
  • ๐Ÿฉบ Host log handler, strict-hook load policy, and structured load/runtime errors

WasmPatch Architecture

Architecture at a glance

flowchart LR
    subgraph Author["โœ๏ธ Author side"]
        C["patch.c"]
        CLI["Tool/wasmpatch build"]
        WASM["patch.wasm<br/>+ .sha256 + signature"]
        C --> CLI --> WASM
    end

    subgraph App["๐Ÿ“ฑ Your iOS / macOS app"]
        LOADER["WAPPatchLoader /<br/>WAPPatchManager"]
        RT["wasm3 interpreter"]
        BRIDGE["Host export bridge (C ABI)"]
        OBJC["Objective-C / Swift runtime"]
        LOADER --> RT --> BRIDGE --> OBJC
    end

    WASM -->|"verify ยท cache ยท deliver"| LOADER
    OBJC -. "replaced IMP via libffi" .-> RT

    style WASM fill:#bbf,color:#000
    style OBJC fill:#bfb,color:#000
Loading

A patch is just a C file compiled to a tiny WebAssembly module. The app verifies and loads it into a sandboxed wasm3 interpreter, whose only powers are the host functions WasmPatch exports โ€” that bridge is what reaches into the live Objective-C / Swift runtime.


โœจ Features

Feature Description
๐Ÿงฑ WASM Compilation Compile C code to WebAssembly with clang/LLVM
๐Ÿ”— Objective-C Bridge Call any Obj-C class or method from WebAssembly
๐Ÿ”„ Method Replacement Hot-fix by replacing Obj-C methods at runtime
๐ŸŽ Cross-Platform Works on both iOS and macOS
๐Ÿ“ Struct Bridging Pass/return geometry structs and arbitrary by-value structs โ€” including unions & bitfields (alloc_struct, field + bit accessors)
โœ๏ธ Author Ergonomics WAP_REPLACE_* macros (typos fail to compile), scope cleanup pools, call_*_3/4
๐Ÿ› ๏ธ Runtime Diagnostics Host log handler, strict-hook policy, structured load/runtime errors
๐Ÿ“ฆ SPM + CocoaPods Swift Package Manager and CocoaPods integration
๐Ÿงฉ Block Callbacks Invoke received blocks (invoke_block) and create blocks to pass into Obj-C (create_block)
๐Ÿฆ… Swift Support @objc dynamic hooking + hookable-surface scanner โ€” see SWIFT.md
๐ŸŒ Remote Delivery WAPPatchManager โ€” fetch, SHA-256 verify, cache, apply
๐Ÿ” Patch Signing EC P-256 / ECDSA signature verification before load (Tool/wasmpatch sign)
๐Ÿงช Regression Assets Test case bundle and fixture hosts for bridge validation

๐Ÿ—๏ธ How It Works

graph TD
    A[C Code] --> B[clang/LLVM]
    B --> C[WebAssembly Module]
    C --> D[WasmPatch Runtime]
    D --> E[Objective-C Runtime]
    E --> F[Hot-fix Applied!]
    
    style A fill:#f9f,color:#000
    style C fill:#bbf,color:#000
    style F fill:#bfb,color:#000
Loading
  1. Write your patch logic in C
  2. Compile to WebAssembly using clang/LLVM
  3. Load the wasm module in your app
  4. Call Objective-C classes/methods from WebAssembly
  5. Replace methods on the fly

๐Ÿš€ Quick Start

Prerequisites

# Install LLVM with WebAssembly target
brew install llvm

# Or use the provided script
sh Tool/install-llvm.sh

1. Clone and Setup

git clone https://github.com/everettjf/WasmPatch.git
cd WasmPatch

Integrate into your app via Swift Package Manager:

// Package.swift
.package(url: "https://github.com/everettjf/WasmPatch.git", branch: "master")

or CocoaPods (pod 'WasmPatch'). Swift apps: see SWIFT.md for what @objc dynamic methods can be hooked and how value/struct types bridge.

2. Compile a Patch

# Check the toolchain is ready (clang wasm target, wasm-ld, SDK header)
Tool/wasmpatch doctor

# Compile a patch โ€” the author SDK header <wasmpatch.h> is on the include path
# automatically, and a .sha256 + .meta.json are emitted next to the .wasm.
Tool/wasmpatch build your_patch.c
Tool/wasmpatch build your_patch.c build/your_patch.wasm

# (the older entry point still works)
sh Tool/build-patch.sh your_patch.c

Patch sources just #include <wasmpatch.h> and use the ergonomic macros:

#include <wasmpatch.h>

WAPObject my_token(WAPObject self, const char *cmd) {
    return new_objc_nsstring("patched");
}

int entry() {
    // Registered name is derived from the real symbol โ€” a typo won't compile.
    WAP_REPLACE_CLASS(MyClass, "token", my_token);

    WAP_POOL_BEGIN(pool);                       // scope-based cleanup
    WAPObject s = WAP_KEEP(pool, new_objc_nsstring("hi"));
    call_class_method_1("Logger", "log:", s);
    WAP_POOL_END(pool);                         // frees everything kept
    return 0;
}

3. Load in Your App

#import <WasmPatch/WAPPatchLoader.h>

NSError *error = nil;
WAPPatchLoaderOptions *options = [WAPPatchLoader recommendedOptions];
options.expectedSHA256Hex = @"<optional sha256>";

BOOL success = [WAPPatchLoader loadPatchNamed:@"your_patch"
                                     inBundle:NSBundle.mainBundle
                                      options:options
                                        error:&error];

if (!success) {
    NSLog(@"load failed: %@", error.localizedDescription);
    NSLog(@"runtime detail: %@", error.userInfo[WAPPatchLoaderRuntimeMessageKey]);
}

Low-level C API is still available when you need it:

#import <WasmPatch/WasmPatch.h>

BOOL success = wap_load_file("your_patch.wasm");
if (success) {
    NSLog(@"loaded");
} else {
    NSLog(@"load failed: %s", wap_last_error());
}

๐Ÿ“ Project Structure

WasmPatch/
โ”œโ”€โ”€ WasmPatch/              # Core framework
โ”‚   โ”œโ”€โ”€ WasmPatch.h         # Public C API
โ”‚   โ”œโ”€โ”€ core/runtime/       # WASM runtime and exports
โ”‚   โ””โ”€โ”€ core/method/        # Obj-C method bridge and hooks
โ”œโ”€โ”€ Tool/                   # Build tools
โ”‚   โ”œโ”€โ”€ c2wasm.sh           # C to WASM compiler
โ”‚   โ””โ”€โ”€ install-llvm.sh     # LLVM installer
โ”œโ”€โ”€ TestCase/               # Test cases
โ”‚   โ”œโ”€โ”€ compile-testcase.sh # Test compiler
โ”‚   โ””โ”€โ”€ WasmPatch-TestCase/ # Sample host classes and wasm fixtures
โ”œโ”€โ”€ Image/                  # Documentation images
โ”œโ”€โ”€ Demo/                   # Demo projects
โ”‚   โ”œโ”€โ”€ iOS/               # iOS demo (Objective-C)
โ”‚   โ”œโ”€โ”€ macOS/             # macOS demo (Objective-C)
โ”‚   โ””โ”€โ”€ WasmPatch-SwiftUI/ # macOS SwiftUI app โ€” live hot-patch of an @objc dynamic method
โ””โ”€โ”€ README.md

๐Ÿ’ป Examples

Public Runtime API

bool wap_load_file(const char * path);
bool wap_load_data(const void * bytes, unsigned int size);
void wap_reset_runtime(void);
bool wap_runtime_is_loaded(void);
const char * wap_last_error(void);

High-Level Objective-C API

NSError *error = nil;
WAPPatchLoaderOptions *options = [WAPPatchLoader recommendedOptions];
options.allowReload = YES;
options.resetBeforeLoad = YES;

[WAPPatchLoader loadPatchAtPath:path options:options error:&error];
[WAPPatchLoader loadPatchNamed:@"objc" inBundle:bundle options:options error:&error];
[WAPPatchLoader loadPatchData:data options:options error:&error];
[WAPPatchLoader reset];

Error handling:

if (error.code == WAPPatchLoaderErrorCodeSHA256Mismatch) {
    NSLog(@"patch tampered: %@", error.userInfo[WAPPatchLoaderRuntimeMessageKey]);
}

Call Objective-C from WASM

// advanced_patch.c
#include <wasmpatch.h>

int entry() {
    WAPObject message = new_objc_nsstring("WasmPatch detected request");
    call_class_method_1("NetworkManager", "logRequest:", message);
    dealloc_object(message);

    replace_instance_method("NetworkManager", "sendRequest:", "wasm_custom_send_request");
    return 0;
}

๐Ÿ› ๏ธ Development

Requirements

Requirement Version Description
macOS 10.14+ Development environment
Xcode 11+ iOS/macOS SDK
LLVM/Clang 14+ C to WASM compilation
wabt latest wasm2wat tooling

Build

# Build the framework
cd WasmPatch/WasmPatch.xcodeproj
xcodebuild -project WasmPatch.xcodeproj \
  -scheme WasmPatch \
  -configuration Release \
  -sdk iphoneos build

# Build for macOS
xcodebuild -project WasmPatch.xcodeproj \
  -scheme WasmPatch \
  -configuration Release \
  -sdk macosx build

Test

# Compile testcase wasm fixtures
cd TestCase
sh compile-testcase.sh

# Compile your own patch with defaults
sh Tool/build-patch.sh path/to/patch.c

# Verify wasm modules
wasm2wat your_patch.wasm -o your_patch.wat

Production validation:

sh Tool/validate-production.sh

macOS host validation only:

sh Tool/run-macos-validation.sh

๐Ÿ“ฑ Platform Support

Platform Support Min Version
iOS โœ… Full 10.0
macOS โœ… Full 10.14
Simulator โœ… Full Same as above

๐Ÿงช Test Cases

Test Case Description
objc.c Objective-C bridge coverage and method replacement fixture
CallMe Host methods for bridge argument/result validation
ReplaceMe Host methods used for runtime replacement verification

Run all tests:

sh TestCase/compile-testcase.sh

๐Ÿ“š Documentation

Full docs live in pages/ (a GitHub Pages site โ€” see pages/DEPLOY.md to publish it):

Reference: Architecture ยท Runtime API ยท Tooling ยท Roadmap

Remote Delivery

WAPPatchManager downloads a patch, verifies its SHA-256, caches it, and applies it:

sequenceDiagram
    participant App
    participant Mgr as WAPPatchManager
    participant Srv as Patch server
    App->>Mgr: fetchPatchFromURL:named:sha256:
    Mgr->>Srv: GET patch.wasm
    Srv-->>Mgr: bytes
    Mgr->>Mgr: verify SHA-256 (integrity)
    Mgr->>Mgr: cache on disk
    Mgr-->>App: completion(cachedPath)
    App->>Mgr: applyCachedPatchNamed:
    Mgr->>Mgr: load + apply via libffi
Loading
#import <WasmPatch/WAPPatchManager.h>

[[WAPPatchManager sharedManager] fetchPatchFromURL:url
                                             named:@"login_fix"
                                            sha256:expectedHash
                                        completion:^(NSString *cachedPath, NSError *error) {
    if (cachedPath) {
        [[WAPPatchManager sharedManager] applyCachedPatchNamed:@"login_fix" options:nil error:nil];
    }
}];

Patch Signing

SHA-256 (expectedSHA256Hex) proves integrity; an EC P-256 signature proves authenticity โ€” a tampered patch can't be re-signed without the private key.

flowchart TD
    KG["wasmpatch keygen<br/>โ†’ patch_key.pem (private)"] --> SIGN["wasmpatch sign"]
    BUILD["wasmpatch build<br/>โ†’ patch.wasm"] --> SIGN
    SIGN --> PUB["publicKeyECBase64<br/>(embedded in app)"]
    SIGN --> SIG["signatureBase64<br/>(shipped with patch)"]
    PUB --> GATE
    SIG --> GATE
    PATCH["delivered patch.wasm"] --> GATE{"verify SHA-256<br/>+ EC P-256"}
    GATE -->|valid| OK["โœ… load and apply"]
    GATE -->|invalid| NO["โ›” refuse:<br/>SignatureInvalid"]

    style OK fill:#bfb,color:#000
    style NO fill:#fbb,color:#000
Loading
# one-time: create a signing key (keep the .pem private)
Tool/wasmpatch keygen patch_key.pem

# sign a built patch; prints publicKeyECBase64 + signatureBase64
Tool/wasmpatch sign your_patch.wasm patch_key.pem
WAPPatchLoaderOptions *options = [WAPPatchLoader recommendedOptions];
options.publicKeyECBase64 = @"<embedded public key (uncompressed point), base64>";
options.signatureBase64   = @"<signature delivered alongside the patch>";

NSError *error = nil;
if (![WAPPatchLoader loadPatchAtPath:path options:options error:&error] &&
    error.code == WAPPatchLoaderErrorCodeSignatureInvalid) {
    NSLog(@"refused: patch is not authentically signed");
}

Current Maturity

  • Author ergonomics (macros, cleanup pools, CLI), struct bridging, completion- handler (block) invocation, host log handler, strict-hook load policy, SPM support, remote delivery (WAPPatchManager), and Swift @objc dynamic hooking are in place and exercised end-to-end (Tool/validate-*.sh).
  • Bidirectional block bridging, EC P-256 patch signing, and generic by-value struct bridging (including structs with unions and bitfields) are all in place. Remaining edges (bare top-level unions, signing-key distribution tooling) are noted in ROADMAP.md.

Release Checklist

sh Tool/build-patch.sh your_patch.c
sh Tool/validate-production.sh

If both pass, the current repo state is ready for internal release and integration validation.


๐Ÿค Contributing

Contributions are welcome! Areas to help:

  • ๐Ÿ› Bug fixes
  • โœจ New features
  • ๐Ÿ“ Documentation
  • ๐Ÿงช Test cases
  • ๐Ÿ’ก Performance improvements

๐Ÿ“œ License

WasmPatch is released under the MIT License.


๐Ÿ™ Acknowledgements

Inspired by:


๐Ÿ“ˆ Star History

Star History Chart


๐Ÿ“ž Support

GitHub Issues WeChat

ๆœ‰้—ฎ้ข˜๏ผŸๅŽป Issues ๆ้—ฎ๏ผ


Made with โค๏ธ by Everett

Project Link: https://github.com/everettjf/WasmPatch

About

๐ŸงฑYet Another Patch Module for iOS/macOS via WebAssembly

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.