Skip to content

Commit

Permalink
Merge pull request icegreentee#441 from segfault-bilibili/rollup-7.2.4
Browse files Browse the repository at this point in the history
【7.2.4】使用nodejs执行音频修正
  • Loading branch information
segfault-bilibili committed Jun 5, 2023
2 parents 844fcf8 + aee75fd commit 32d179e
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 30 deletions.
229 changes: 229 additions & 0 deletions audiofix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
"nodejs";

const fs = require("fs");
const path = require("path");

const EM_AARCH64 = 0xb7, EM_ARM = 0x28;
const ELFCLASS64 = 2, ELFCLASS32 = 1;

function parseElf(elf) {
let result = {};

// parse elf header
const read_e_ident = elf.subarray(0, 16);
if (Buffer.compare(Buffer.from([0x7f, 0x45, 0x4c, 0x46]), read_e_ident.subarray(0, 4)) != 0) {
throw new Error("not ELF");
}

const eh = result.elf_header = {
e_ident: {
ei_class_2: read_e_ident.readUInt8(4),
ei_data: read_e_ident.readUInt8(5),
ei_version: read_e_ident.readUInt8(6),
ei_osabi: read_e_ident.readUInt8(7),
ei_abiversion: read_e_ident.readUInt8(8),
ei_nident_SIZE: read_e_ident.readUInt8(0xf),
},
e_type: elf.readUInt16LE(0x10),
e_machine: elf.readUInt16LE(0x12),
e_version: elf.readUInt32LE(0x14),
}

if (result.elf_header.e_ident.ei_nident_SIZE != 0) {
throw new Error("ei_nident_SIZE != 0");
}

let is64 = true;
let e_flags_offset = 0x30;
switch (eh.e_ident.ei_class_2) {
case ELFCLASS64:
if (eh.e_machine != EM_AARCH64) {
throw new Error(`e_machine (${eh.e_machine}) != EM_AARCH64`);
}
is64 = true;
eh.e_entry_START_ADDRESS = Number(elf.readBigUInt64LE(0x18));
eh.e_phoff_PROGRAM_HEADER_OFFSET_IN_FILE = Number(elf.readBigUInt64LE(0x20));
eh.e_shoff_SECTION_HEADER_OFFSET_IN_FILE = Number(elf.readBigUInt64LE(0x28));
e_flags_offset = 0x30;
break;
case ELFCLASS32:
if (eh.e_machine != EM_ARM) {
throw new Error(`eh.e_machine (${eh.e_machine}) != EM_ARM`);
}
is64 = false;
addrLen = 4;
eh.e_entry_START_ADDRESS = elf.readUInt32LE(0x18);
eh.e_phoff_PROGRAM_HEADER_OFFSET_IN_FILE = elf.readUInt32LE(0x1c);
eh.e_shoff_SECTION_HEADER_OFFSET_IN_FILE = elf.readUInt32LE(0x20);
e_flags_offset = 0x24;
break;
default:
throw new Error(`unknown ei_class_2 = ${eh.e_ident.ei_class_2}`);
}

eh.e_flags = elf.readUInt32LE(e_flags_offset);
eh.e_ehsize_ELF_HEADER_SIZE = elf.readUInt16LE(e_flags_offset + 4);
eh.e_phentsize_PROGRAM_HEADER_ENTRY_SIZE_IN_FILE = elf.readUInt16LE(e_flags_offset + 6);
eh.e_phnum_NUMBER_OF_PROGRAM_HEADER_ENTRIES = elf.readUInt16LE(e_flags_offset + 8);
eh.e_shentsize_SECTION_HEADER_ENTRY_SIZE = elf.readUInt16LE(e_flags_offset + 10);
eh.e_shnum_NUMBER_OF_SECTION_HEADER_ENTRIES = elf.readUInt16LE(e_flags_offset + 12);
eh.e_shtrndx_STRING_TABLE_INDEX = elf.readUInt16LE(e_flags_offset + 14);


// parse section header
const sh = result.section_header_table = [];

const shoff = eh.e_shoff_SECTION_HEADER_OFFSET_IN_FILE;
const shnum = eh.e_shnum_NUMBER_OF_SECTION_HEADER_ENTRIES;
const shentsize = eh.e_shentsize_SECTION_HEADER_ENTRY_SIZE;
const read_shtab = elf.subarray(shoff, shoff + shentsize * shnum);
const shtrndx = eh.e_shtrndx_STRING_TABLE_INDEX;

const read_shstrtab = elf.subarray(shoff + shentsize * shtrndx);
const strtab_offset = is64 ? Number(read_shstrtab.readBigUInt64LE(24)) : read_shstrtab.readUInt32LE(16);
const strtab_size = is64 ? Number(read_shstrtab.readBigUInt64LE(32)) : read_shstrtab.readUInt32LE(20);
const read_strtab = elf.subarray(strtab_offset, strtab_offset + strtab_size);

for (let i = 0, offset = 0; i < shnum; i++, offset += shentsize) {
let read_entry = read_shtab.subarray(offset, offset + shentsize);
let s_name_off = read_entry.readUInt32LE(0);
let s_name_str = read_strtab.subarray(s_name_off, read_strtab.indexOf(0x00, s_name_off)).toString("ascii");
sh.push({
s_name: {
s_name_off: s_name_off,
s_name_str: s_name_str,
},
s_type: read_entry.readUInt32LE(4),
s_flags: read_entry.readUInt32LE(8),
s_addr: is64 ? Number(read_entry.readBigUInt64LE(16)) : read_entry.readUInt32LE(12),
s_offset: is64 ? Number(read_entry.readBigUInt64LE(24)) : read_entry.readUInt32LE(16),
s_size: is64 ? Number(read_entry.readBigUInt64LE(32)) : read_entry.readUInt32LE(20),
s_link: read_entry.readUInt32LE(is64 ? 40 : 24),
s_info: read_entry.readUInt32LE(is64 ? 44 : 28),
s_addralign: is64 ? Number(read_entry.readBigUInt64LE(48)) : read_entry.readUInt32LE(32),
s_entsize: is64 ? Number(read_entry.readBigUInt64LE(56)) : read_entry.readUInt32LE(36),
});
}


//parse dynamic symbol table
const dynsym = result.dynamic_symbol_table = [];

const dynsym_sec = sh.find((entry) => entry.s_name.s_name_str === ".dynsym");
const dynsym_secoffset = dynsym_sec.s_offset;
const dynsym_secsize = dynsym_sec.s_size;
const dynsym_entsize = dynsym_sec.s_entsize;
if (dynsym_entsize <= 0) {
throw new Error(`dynsym_entsize ${dynsym_entsize} <= 0`);
}
const read_dynsym = elf.subarray(dynsym_secoffset, dynsym_secoffset + dynsym_secsize);

const dynstr_sec = sh.find((entry) => entry.s_name.s_name_str === ".dynstr");
const dynstr_secoffset = dynstr_sec.s_offset;
const dynstr_secsize = dynstr_sec.s_size;
const read_dynstr = elf.subarray(dynstr_secoffset, dynstr_secoffset + dynstr_secsize);
for (
let i = 0, offset = 0;
offset + dynsym_entsize <= dynsym_secsize;
i++, offset += dynsym_entsize
) {
let read_entry = read_dynsym.subarray(offset, offset + dynsym_entsize);
let sym_name_off = read_entry.readUInt32LE(0);
let sym_name_str = read_dynstr.subarray(sym_name_off, read_dynstr.indexOf(0x00, sym_name_off)).toString("ascii");
dynsym.push({
sym_name: {
sym_name_off: sym_name_off,
sym_name_str: sym_name_str,
},
sym_info: read_entry.readUInt8(is64 ? 4 : 12),
sym_other: read_entry.readUInt8(is64 ? 5 : 13),
sym_shndx: read_entry.readUInt16LE(is64 ? 6 : 14),
sym_value: is64 ? Number(read_entry.readBigUInt64LE(8)) : read_entry.readUInt32LE(4),
sym_size: is64 ? Number(read_entry.readBigUInt64LE(16)) : read_entry.readUInt32LE(8),
});
}

return result;
}

function getTargetFunction(elf, info, funcName, funcOffset, bufLen) {
const syment = info.dynamic_symbol_table.find((entry) => entry.sym_name.sym_name_str === funcName);
const offset = syment.sym_value;
const size = syment.sym_size;
const func = elf.subarray(offset, offset + size);
if (funcOffset + bufLen > func.length) throw new Error("funcOffset + bufLen > func.length");
return func.subarray(funcOffset, funcOffset + bufLen);
}

function checkFunction(elf, info, funcName, funcOffset, buf) {
const target = getTargetFunction(elf, info, funcName, funcOffset, buf.length);
return Buffer.compare(target, buf) == 0;
}

function patchFunction(elf, info, funcName, funcOffset, buf) {
const target = getTargetFunction(elf, info, funcName, funcOffset, buf.length);
buf.copy(target);
}

const wdir = path.join(process.cwd(), "audio_sr_fix");
fs.writeFileSync(path.join(wdir, "running"), "");

const libname = "libmadomagi_native.so";
const funcToPatch = "criNcv_GetHardwareSamplingRate_ANDROID";
const abiList = {
"arm64-v8a": [
{
funcName: funcToPatch,
checkList: [
{
offset: 8,
buf: [0xc0, 0x03, 0x5f, 0xd6],
}
],
patchList: [
{
offset: 4,
buf: [0x00, 0x70, 0x97, 0x52],
},
],
},
],
"armeabi-v7a": [
{
funcName: funcToPatch,
checkList: [
{
offset: 8,
buf: [0x1e, 0xff, 0x2f, 0xe1],
}
],
patchList: [
{
offset: 4,
buf: [0x80, 0x0b, 0x0b, 0xe3],
},
],
},
],
}

for (let abi in abiList) {
let filepath = path.join(wdir, "lib", abi, libname);
if (!fs.existsSync(filepath)) {
console.log(`skipped nonexist file ${filepath}`);
continue;
}
let filedata = fs.readFileSync(filepath);
console.log(`patching ${filepath}`);
let info = parseElf(filedata);
abiList[abi].forEach((patchInfo) => {
let mismatch = patchInfo.checkList.find((check) => !checkFunction(filedata, info, patchInfo.funcName, check.offset, Buffer.from(check.buf)));
if (mismatch != null) throw new Error("check failed");
patchInfo.patchList.forEach((patch) => patchFunction(filedata, info, patchInfo.funcName, patch.offset, Buffer.from(patch.buf)));
});
let writeToPath = path.join(wdir, "lib", abi, libname);
fs.writeFileSync(writeToPath, filedata);
console.log(`written patched file to ${writeToPath}`);
};

fs.writeFileSync(path.join(wdir, "done"), "");
71 changes: 44 additions & 27 deletions floatUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -13101,10 +13101,14 @@ function algo_init() {

initOCR();

toastLog("半自动辅助开荒脚本能够在一个章节(section)内自动选BATTLE进行周回;");
toastLog("且支持在第一回合自动凑连携(可在设置中关闭);");
toastLog("以及支持地图型周回,但在找不到没打过(new)的关卡时不会自动拖动地图;");
toastLog("另外,不会嗑药,也不会处理掉线等情况。");
toast("半自动辅助开荒脚本能够在一个章节(section)内自动选BATTLE进行周回;");
toast("且支持在第一回合自动凑连携(可在设置中关闭);");
threads.start(function () {
// avoid exceeded toast quota
sleep(6000);
toast("以及支持地图型周回,但在找不到没打过(new)的关卡时不会自动拖动地图;");
toast("另外,不会嗑药,也不会处理掉线等情况。");
});

log("缩放图片...");
resizeKnownImgs();//必须放在initialize后面
Expand Down Expand Up @@ -13213,6 +13217,14 @@ function algo_init() {
return;
}

if (parseInt(getProjectVersion().split(".").join("")) < 724) {
alert("请升级",
"请先下载最新APK安装包(而不是在线更新),升级auto脚本到7.2.4或以上。\n"
+"详情请见app底部QQ群。"
);
return;
}

try {
privShell("id");
} catch (e) {
Expand Down Expand Up @@ -13250,20 +13262,6 @@ function algo_init() {
}

const extractDir = files.join(files.cwd(), "audio_sr_fix");
const searchPatterns = [
//3.0.2
{
abi: "arm64-v8a",
pattern: "\x08\x7A\x00\xD0\x00\x51\x4F\xB9\xC0\x03\x5F\xD6",
replace: "\x08\x7A\x00\xD0\x00\x70\x97\x52\xC0\x03\x5F\xD6"
},
{
abi: "armeabi-v7a",
pattern: "\x04\x00\x9F\xE5\x00\x00\x9F\xE7\x1E\xFF\x2F\xE1\xDC\x41\xBC\x00",
replace: "\x04\x00\x9F\xE5\x80\x0B\x0B\xE3\x1E\xFF\x2F\xE1\xDC\x41\xBC\x00"
},
]

let fileNames = [];
try {
files.ensureDir(files.join(extractDir, "lib"));
Expand All @@ -13272,8 +13270,7 @@ function algo_init() {
while (zipentries.hasMoreElements()) {
let entry = zipentries.nextElement();
let name = entry.getName();
let searchPattern = searchPatterns.find((p) => name === "lib/" + p.abi + "/libmadomagi_native.so");
if (searchPattern == null) continue;
if (!name.match(/^lib\/(arm64-v8a|armeabi-v7a)\/libmadomagi_native\.so$/)) continue;
if (entry.isDirectory()) continue;

let path = files.join(extractDir, name);
Expand All @@ -13292,19 +13289,39 @@ function algo_init() {
}
stream.close();

files.writeBytes(path, bytes);
log("written to ["+path+"]");

if (isRevert) {
log("keep file as-is");
} else if (name.match(/\.so$/)) {
let count = binaryReplaceText(bytes, searchPattern.pattern, searchPattern.replace);
log("replaced "+count+" occurrences in ["+name+"]");
if (count == 0) {
dialogs.alert("未找到特征", "请等待脚本更新适配");
} else {
files.remove(files.join(extractDir, "running"));
files.remove(files.join(extractDir, "done"));
log("starting audiofix.js");
let exec = engines.execScriptFile(files.join(files.cwd(), "audiofix.js"));
for (let deadlineTime = Date.now() + 30000; Date.now() < deadlineTime; ) {
if (files.exists(files.join(extractDir, "running"))) break;
}
if (!files.exists(files.join(extractDir, "running"))) {
log("failed to launch nodejs");
dialogs.alert("启动NodeJS引擎出错", "请下载最新APK安装包更新后重试");
return;
}
let isDone = false;
for (let deadlineTime = Date.now() + 30000; Date.now() < deadlineTime; ) {
if (files.exists(files.join(extractDir, "done"))) {
isDone = true;
break;
}
sleep(1000);
}
if (!isDone) {
exec.getEngine().forceStop();
log("timeout");
dialogs.alert("执行超时");
}
}

files.writeBytes(path, bytes);
log("written to ["+path+"]");
fileNames.push(name);
}
zipfile.close();
Expand Down
3 changes: 2 additions & 1 deletion project.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"build"
],
"packageName": "top.momoe.auto",
"versionName": "7.2.3",
"versionName": "7.2.4",
"versionInfo": "",
"versionCode": 1,
"icon":"./images/icon.png",
Expand All @@ -24,6 +24,7 @@
"armeabi-v7a"
],
"features": {
"nodejs": "enabled",
"builtInOCR": "with-models"
}
}
Loading

0 comments on commit 32d179e

Please sign in to comment.