Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Sources/WeChatTweak/Command.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ struct Command {
try await Command.execute(command: "defaults read \(app.appendingPathComponent("Contents/Info.plist").path) CFBundleVersion")
}

static func patch(app: URL, config: Config) async throws {
try Patcher.patch(binary: app.appendingPathComponent("Contents/MacOS/WeChat"), config: config)
static func patch(app: URL, targets: [Target]) async throws {
try Patcher.patch(binary: app.appendingPathComponent("Contents/MacOS/WeChat"), entries: targets.flatMap { $0.entries })
}

static func resign(app: URL) async throws {
Expand Down
3 changes: 1 addition & 2 deletions Sources/WeChatTweak/Patcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ struct Patcher {
case noArchMatched
}

static func patch(binary: URL, config: Config) throws {
static func patch(binary: URL, entries: [Target.Entry]) throws {
guard FileManager.default.fileExists(atPath: binary.path) else {
throw Error.invalidFile
}

let entries = config.targets.flatMap { $0.entries }
guard !entries.isEmpty else { throw Error.noArchMatched }

let fh = try FileHandle(forUpdating: binary)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
//
// Config.swift
// Target.swift
// WeChatTweak
//
// Created by Sunny Young on 2025/12/5.
//

import Foundation
import MachO

struct Config: Decodable {
enum Arch: String, Decodable {
case arm64
case x86_64
struct Target: Decodable {
struct Entry: Decodable {
enum Arch: String, Decodable {
case arm64
case x86_64

var cpu: UInt32 {
switch self {
case .arm64:
return UInt32(CPU_TYPE_ARM64)
case .x86_64:
return UInt32(CPU_TYPE_X86_64)
var cpu: UInt32 {
switch self {
case .arm64:
return UInt32(CPU_TYPE_ARM64)
case .x86_64:
return UInt32(CPU_TYPE_X86_64)
}
}
}
}

struct Entry: Decodable {
let arch: Arch
let addr: UInt64
let asm: Data
Expand Down Expand Up @@ -62,38 +61,8 @@ struct Config: Decodable {
}
}

struct Target: Decodable {
let identifier: String
let entries: [Entry]

private enum CodingKeys: CodingKey {
case identifier
case entries
}

init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.identifier = try container.decode(String.self, forKey: .identifier)
self.entries = try container.decode([Entry].self, forKey: .entries)
}
}

let version: String
let targets: [Target]

static func load(url: URL) async throws -> [Config] {
if url.isFileURL {
return try JSONDecoder().decode(
[Config].self,
from: Data(contentsOf: url)
)
} else {
return try JSONDecoder().decode(
[Config].self,
from: try await URLSession.shared.data(from: url).0
)
}
}
let identifier: String
let entries: [Entry]
}

private extension Data {
Expand Down
49 changes: 37 additions & 12 deletions Sources/WeChatTweak/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ extension Tweak {
print("------ Current version ------")
print(try await Command.version(app: options.app) ?? "unknown")
print("------ Supported versions ------")
try await Config.load(url: options.config).forEach({ print($0.version) })
try await Tweak.versions().forEach { print($0) }
Darwin.exit(EXIT_SUCCESS)
}
}
Expand All @@ -36,25 +36,21 @@ extension Tweak {

mutating func run() async throws {
print("------ Version ------")
let version = try await Command.version(app: options.app)
print("WeChat version: \(version ?? "unknown")")

print("------ Config ------")
guard let config = (try await Config.load(url: options.config)).first(where: { $0.version == version }) else {
guard let version = try await Command.version(app: self.options.app), let targets = try await Tweak.load(version: version) else {
throw Error.unsupportedVersion
}
print("Matched config: \(config)")
print("\(version)")

print("------ Patch ------")
try await Command.patch(
app: options.app,
config: config
app: self.options.app,
targets: targets
)
print("Done!")

print("------ Resign ------")
try await Command.resign(
app: options.app
app: self.options.app
)
print("Done!")

Expand Down Expand Up @@ -101,7 +97,7 @@ struct Tweak: AsyncParsableCommand {

@Option(
name: .shortAndLong,
help: "Local path or Remote URL of config.json",
help: "Local path or Remote URL of config (default: derived from app version)",
transform: {
if FileManager.default.fileExists(atPath: $0) {
return URL(fileURLWithPath: $0)
Expand All @@ -113,7 +109,7 @@ struct Tweak: AsyncParsableCommand {
}
}
)
var config: URL = URL(string:"https://raw.githubusercontent.com/sunnyyoung/WeChatTweak/refs/heads/master/config.json")!
var config: URL? = nil
}

static let configuration = CommandConfiguration(
Expand All @@ -131,6 +127,35 @@ struct Tweak: AsyncParsableCommand {
}
}

extension Tweak {
static func load(url: URL) async throws -> [Target] {
let data = try await {
if url.isFileURL {
return try Data(contentsOf: url)
} else {
return try await URLSession.shared.data(from: url).0
}
}()
return try JSONDecoder().decode([Target].self, from: data)
}

static func load(version: String) async throws -> [Target]? {
guard try await Tweak.versions().contains(version) else {
return nil
}
return try await Self.load(url: URL(string: "https://raw.githubusercontent.com/sunnyyoung/WeChatTweak/master/Versions/\(version).json")!)
}

static func versions() async throws -> [String] {
let data = try await URLSession.shared.data(
for: URLRequest(
url: URL(string: "https://api.github.com/repos/sunnyyoung/WeChatTweak/contents/Versions")!
)
)
return (try JSONSerialization.jsonObject(with: data.0) as? [[String: Any]])?.compactMap { ($0["name"] as? NSString)?.deletingPathExtension } ?? []
}
}

Task {
await Tweak.main()
}
Expand Down
82 changes: 82 additions & 0 deletions Versions/31927.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
[
{
"identifier": "revoke",
"entries": [
{
"arch": "arm64",
"addr": "103dba3d0",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "startUpdater",
"entries": [
{
"arch": "arm64",
"addr": "1001ea41c",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "startBackgroundUpdatesCheck",
"entries": [
{
"arch": "arm64",
"addr": "1001ed3b4",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "checkForUpdates",
"entries": [
{
"arch": "arm64",
"addr": "1001ecf9c",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "enableAutoUpdate",
"entries": [
{
"arch": "arm64",
"addr": "1001ed920",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "automaticallyDownloadsUpdates",
"entries": [
{
"arch": "arm64",
"addr": "1001f6ee8",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "canCheckForUpdate",
"entries": [
{
"arch": "arm64",
"addr": "1001f6ef8",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "multiInstance",
"entries": [
{
"arch": "arm64",
"addr": "1001e1c10",
"asm": "20008052C0035FD6"
}
]
}
]
22 changes: 22 additions & 0 deletions Versions/31960.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"identifier": "revoke",
"entries": [
{
"arch": "arm64",
"addr": "10408a408",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "multiInstance",
"entries": [
{
"arch": "arm64",
"addr": "1001e4a38",
"asm": "20008052C0035FD6"
}
]
}
]
82 changes: 82 additions & 0 deletions Versions/32281.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
[
{
"identifier": "revoke",
"entries": [
{
"arch": "arm64",
"addr": "103db33e0",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "startUpdater",
"entries": [
{
"arch": "arm64",
"addr": "1001e9ed0",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "startBackgroundUpdatesCheck",
"entries": [
{
"arch": "arm64",
"addr": "1001ecb10",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "checkForUpdates",
"entries": [
{
"arch": "arm64",
"addr": "1001ec73c",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "enableAutoUpdate",
"entries": [
{
"arch": "arm64",
"addr": "1001ecfc0",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "automaticallyDownloadsUpdates",
"entries": [
{
"arch": "arm64",
"addr": "1001f59e0",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "canCheckForUpdate",
"entries": [
{
"arch": "arm64",
"addr": "1001f59e0",
"asm": "00008052C0035FD6"
}
]
},
{
"identifier": "multiInstance",
"entries": [
{
"arch": "arm64",
"addr": "1001e1a74",
"asm": "20008052C0035FD6"
}
]
}
]
Loading