为知笔记
启动docker镜像
根据其官网 https://www.wiz.cn/zh-cn/docker 说明,使用如下命令即可启动
bash
docker pull wiznote/wizserver:latest
docker run --name wiz --restart=always -it -d \
-v pwd/wizdata:/wiz/storage \
-v /etc/localtime:/etc/localtime \
-p 80:80 -p 9269:9269/udp wiznote/wizserver
初探授权
-
启动好之后,默认授权限制只能有5个用户。
-
进入docker容器,查看基本信息。
执行
docker exec -it wiz bash进入容器,可以看到- 后端主要使用node实现并用pm2管理,nginx反代,数据库mysql
- node版本v8.11.2,v8版本6.2.414.54点击查看执行结果
# ps -aef
UID PID CMD
root 1 bash /wiz/app/entrypoint.sh
root 33 /usr/bin/redis-server 127.0.0.1:6379
mysql 53 /usr/sbin/mysqld
root 59 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx 60 nginx: worker process
nginx 61 nginx: worker process
root 119 PM2 v4.5.0: God Daemon (/root/.pm2)
root 129 node /root/.pm2/modules/pm2-logrotate/node_modules/pm2-logrotate/app.js
root 137 node /wiz/app/wizserver/app.js
root 157 node /wiz/app/wizserver/app.js
root 173 node /wiz/app/wizserver/app.js
root 189 node /wiz/app/wizserver/app.js
root 205 node /wiz/app/wizserver/app.js
root 221 node /wiz/app/wizserver/app.js
root 240 node /wiz/app/wizserver/app.js
root 246 crond -n
root 256 bash
root 270 ps -aef
# node -v
v8.11.2
# node -p process.versions.v8
6.2.414.54
# pm2 list
┌─────┬──────────────────┬
│ id │ name │
├─────┼──────────────────┼
│ 1 │ as │
│ 6 │ cloud │
│ 4 │ index │
│ 2 │ note │
│ 7 │ office │
│ 5 │ search │
│ 3 │ ws │
└─────┴──────────────────┴
-
分析代码发现后缀为jsc的文件
bash
ll /wiz/app/wizserver/common/
total 536
-rw-r--r-- 1 root root 8792 Dec 23 2020 alicloud_tools.jsc
-rw-r--r-- 1 root root 9984 Dec 23 2020 client_tools.jsc
-rw-r--r-- 1 root root 7024 Dec 23 2020 cookie_tools.jsc
-rw-r--r-- 1 root root 2352 Dec 23 2020 date_tools.jsc
-rw-r--r-- 1 root root 27528 Dec 23 2020 db_tools.jsc
......进一步分析发现,这是通过bytenodehttps://github.com/bytenode/bytenode工具编译成了v8的字节码。
在各种搜索之后发现,目前还没有相关的反汇编、反编译工具。
唯一相关项目https://github.com/PositiveTechnologies/ghidra_nodejs是GHIDRA的插件,但node版本和我们不匹配
反汇编v8字节码,改造d8
通过v8源码分析发现,v8本身是有反汇编功能,node可通过--print-bytecode参数开启。
但只能反汇编源码,无法反汇编jsc文件。为了反汇编字节码只能通过修改v8来实现。
d8 https://v8.dev/docs/d8 是v8的开发工具,为了简单起见决定对d8进行修改。
反汇编jsc思路
- jsc实际是由
v8::internal::CodeSerializer::Serialize方法生成 - 反汇编需要调用
v8::internal::BytecodeArray::Disassemble方法生成
反序列v8::internal::CodeSerializer::Deserialize原型
c++
MUST_USE_RESULT static MaybeHandle<SharedFunctionInfo> Deserialize(
Isolate* isolate, ScriptData* cached_data, Handle<String> source);
其中参数cached_data,可通过ScriptData的构造函数ScriptData(const byte* data, int length);构造
其中返回值SharedFunctionInfo对象有bytecode_array方法,可以获得BytecodeArray来进行反汇编
c++
1
2
3
4
BytecodeArray* SharedFunctionInfo::bytecode_array() const {
DCHECK(HasBytecodeArray());
return BytecodeArray::cast(function_data());
}
于是思路自然而然就有了
- 读取jsc,构造
ScriptData对象 - 反 序列化,获取
SharedFunctionInfo对象 - 反汇编,通过
bytecode_array获取BytecodeArray,并调用Disassemble反汇编
搭建v8编译环境
bash
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=`pwd`/depot_tools:"$PATH"
export HTTPS_PROXY=http://172.31.0.1:18080 # 设置代理
gclient sync # 更新工具链
fetch v8 # 获取v8代码
cd v8
git checkout 6.2.414.46 # 切换至需要的分支
gclient sync # 根据分支再次更新工具链
tools/dev/v8gen.py x64.release -- \
v8_enable_disassembler=true \
v8_enable_object_print=true # 配置编译选项
ninja -C out.gn/x64.release d8 # 编译d8
`v8_enable_disassembler`和`v8_enable_object_print`一定要开启,否则反汇编时不显示常量内容
### [](https://guage.cool/wiz-license/#%E4%BF%AE%E6%94%B9d8%E4%BB%A3%E7%A0%81-d8-cc "修改d8代码(d8.cc)")修改d8代码(d8.cc)
在Shell类增加LoadJSC方法
c++
static void Disassemble(v8::internal::BytecodeArray* bytecode) {
internal::OFStream os(stdout);
bytecode->Disassemble(os);
auto consts = bytecode->constant_pool();
for (int i = 0; i < consts->length(); i++) {
auto obj = consts->get(i);
if (obj->IsSharedFunctionInfo()) {
auto shared = v8::internal::SharedFunctionInfo::cast(obj);
os << "Function name " << shared->name()->ToCString().get() << "\n";
Disassemble(shared->bytecode_array());
}
}
}
void Shell::LoadJSC(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
for (int i = 0; i < args.Length(); i++) {
String::Utf8Value filename(args.GetIsolate(), args[i]);
if (*filename == NULL) {
Throw(args.GetIsolate(), "Error loading file");
return;
}
int length = 0;
auto filedata = reinterpret_cast<uint8_t*>(ReadChars(*filename, &length));
if (filedata == NULL) {
Throw(args.GetIsolate(), "Error reading file");
return;
}
auto scriptdata = new i::ScriptData(filedata, length);
auto source = isolate->factory()
->NewStringFromUtf8(i::CStrVector("source"))
.ToHandleChecked();
auto fun = i::CodeSerializer::Deserialize(isolate, scriptdata, source)
.ToHandleChecked();
Disassemble(fun->bytecode_array());
}
}
注册为全局函数,在Shell::CreateGlobalTemplate中添加代码
global_template->Set(
String::NewFromUtf8(isolate, "loadjsc", NewStringType::kNormal)
.ToLocalChecked(),
FunctionTemplate::New(isolate, LoadJSC));
