Some Assembly Required 2
https://play.picoctf.org/practice/challenge/131
Writeup(未完)t6o_o6t.icon
未完のWriteupとはt6o_o6t.icon
Reversingのようなことをさせてくる問題 t6o_o6t.icon
変数名が難読化されていたので意味を予想したt6o_o6t.icon
argsと命名したものが本当にargsのような意味なのかは分からない
定数の配列だと思う
fに渡して更に難読化しようとしている
fは、受け取った数値から0xc3(=195)を引いてindexとして、argsの特定要素を参照して返す
code:reverse_1.js
const args = 'copy_char', 'value', '207aLjBod', '1301420SaUSqf', '233ZRpipt', '2224QffgXU', 'check_flag', '408533hsoVYx', 'instance', '278338GVFUrH', 'Correct!', '549933ZVjkwI', 'innerHTML', 'charCodeAt', './aD8SvhyVkb', 'result', '977AzKzwq', 'Incorrect!', 'exports', 'length', 'getElementById', '1jIrMBu', 'input', '615361geljRK';
const f = function(arg1, arg2) {
arg1 = arg1 - 0xc3;
let val = argsarg1;
return val;
};
(function(str, expected) {
const f2 = f;
while (!![]) {
try {
const f2result = -parseInt(f2(0xc8)) * -parseInt(f2(0xc9)) + -parseInt(f2(0xcd)) + parseInt(f2(0xcf)) + parseInt(f2(0xc3)) + -parseInt(f2(0xc6)) * parseInt(f2(0xd4)) + parseInt(f2(0xcb)) + -parseInt(f2(0xd9)) * parseInt(f2(0xc7));
if (f2result === expected)
break;
else
str'push'(str'shift'());
} catch (e) {
str'push'(str'shift'());
}
}
}(args, 0x4bb06));
let exports;
(async()=>{
const f2 = f;
let fetchresult = await fetch(f2(0xd2))
, wasmresult = await WebAssembly'instantiate'(await fetchresult'arrayBuffer'())
, _0x5c0ffa = wasmresultf2(0xcc);
exports = _0x5c0ffaf2(0xd6);
}
)();
function onButtonPress() {
const f2 = f;
let documentpart = documentf2(0xd8)(f2(0xda))f2(0xc5);
for (let i = 0x0; i < documentpart'length'; i++) {
exportsf2(0xc4)(documentpartf2(0xd1)(i), i);
}
exports'copy_char'(0x0, documentpartf2(0xd7)),
exportsf2(0xca)() == 0x1 ? document'getElementById'(f2(0xd3))f2(0xd0) = f2(0xce) : documentf2(0xd8)(f2(0xd3))'innerHTML' = f2(0xd5);
}
argsの値は、parseIntに渡される値がNaNになる限り後ろから前へ周り続けそうt6o_o6t.icon
即時関数をローカルで実行してみて、strの値を見たt6o_o6t.icon
普通にChrome DevToolsでブレークポイントを仕掛けたら良かった
code:str.js
[
'615361geljRK', 'copy_char',
'value', '207aLjBod',
'1301420SaUSqf', '233ZRpipt',
'2224QffgXU', 'check_flag',
'408533hsoVYx', 'instance',
'278338GVFUrH', 'Correct!',
'549933ZVjkwI', 'innerHTML',
'charCodeAt', './aD8SvhyVkb',
'result', '977AzKzwq',
'Incorrect!', 'exports',
'length', 'getElementById',
'1jIrMBu', 'input'
]
この状態で、onButtonPressやasyncに渡される値がどれかを見る必要がある
asyncの即時関数は、wasmファイルをfetchしている
このなかでcheck_flag
code:reverse_2.js
const args = 'copy_char', 'value', '207aLjBod', '1301420SaUSqf', '233ZRpipt', '2224QffgXU', 'check_flag', '408533hsoVYx', 'instance', '278338GVFUrH', 'Correct!', '549933ZVjkwI', 'innerHTML', 'charCodeAt', './aD8SvhyVkb', 'result', '977AzKzwq', 'Incorrect!', 'exports', 'length', 'getElementById', '1jIrMBu', 'input', '615361geljRK';
const f = function(arg1, arg2) {
arg1 = arg1 - 0xc3;
let val = argsarg1;
return val;
};
(function(str, expected) {
const f2 = f;
while (!![]) {
try {
const f2result = -parseInt(f2(0xc8)) * -parseInt(f2(0xc9)) + -parseInt(f2(0xcd)) + parseInt(f2(0xcf)) + parseInt(f2(0xc3)) + -parseInt(f2(0xc6)) * parseInt(f2(0xd4)) + parseInt(f2(0xcb)) + -parseInt(f2(0xd9)) * parseInt(f2(0xc7));
if (f2result === expected)
break;
else
str'push'(str'shift'());
} catch (e) {
str'push'(str'shift'());
}
}
}(args, 0x4bb06));
let exports;
(async()=>{
const f2 = f;
let fetchresult = await fetch('./aD8SvhyVkb')
, wasmresult = await WebAssembly'instantiate'(await fetchresult'arrayBuffer'())
, instance = wasmresult'instance';
exports = instance'export';
// wasmの関数をexportsから呼び出せるようにする?
}
)();
function onButtonPress() {
const f2 = f;
let input = document.getElementById('input').value;
for (let i = 0; i < input.length; i++) {
exports.copy_char(input.charCodeAt(i), i);
// i 文字目に
}
exports.copy_char(0, input.length),
exports.check_flag() == 1 ? document.getElementById('result').innerHTML = 'Correct!' : document.getElementById('result').innerHTML = 'Incorrect!';
}
読めた!!t6o_o6t.icon
copy_charはただcopyしているだけだと思う
最後にヌル文字を付加して終了
check_flagで1が返るようにしたい
wasmを読む必要がある?
wasmのdecompilerはある?
./aD8SvhyVkbの中身をwasm-decompileに突っ込んだ結果 ↓
code:out.js
export memory memory(initial: 2, max: 0);
global g_a:int = 66864;
export global input:int = 1072;
export global dso_handle:int = 1024;
export global data_end:int = 1328;
export global global_base:int = 1024;
export global heap_base:int = 66864;
export global memory_base:int = 0;
export global table_base:int = 1;
table T_a:funcref(min: 1, max: 1);
data d_xakgKNsmi11991nkjlii1j0nmm09(offset: 1024) =
"xakgK\Ns><m:i1>1991:nkjl<ii1j0n=mm09;<i:u\00\00";
export function wasm_call_ctors() {
}
export function strcmp(a:int, b:int):int {
var c:int = g_a;
var d:int = 32;
var e:int = c - d;
e6:int = a;
e5:int = b;
var f:int = e6:int;
e4:int = f;
var g:int = e5:int;
e3:int = g;
loop L_b {
var h:ubyte_ptr = e4:int;
var i:int = 1;
var j:int = h + i;
e4:int = j;
var k:int = h0;
e11:byte = k;
var l:ubyte_ptr = e3:int;
var m:int = 1;
var n:int = l + m;
e3:int = n;
var o:int = l0;
e10:byte = o;
var p:int = e11:ubyte;
var q:int = 255;
var r:int = p & q;
if (r) goto B_c;
var s:int = e11:ubyte;
var t:int = 255;
var u:int = s & t;
var v:int = e10:ubyte;
var w:int = 255;
var x:int = v & w;
var y:int = u - x;
e7:int = y;
goto B_a;
label B_c:
var z:int = e11:ubyte;
var aa:int = 255;
var ba:int = z & aa;
var ca:int = e10:ubyte;
var da:int = 255;
var ea:int = ca & da;
var fa:int = ba;
var ga:int = ea;
var ha:int = fa == ga;
var ia:int = 1;
var ja:int = ha & ia;
if (ja) continue L_b;
}
var ka:int = e11:ubyte;
var la:int = 255;
var ma:int = ka & la;
var na:int = e10:ubyte;
var oa:int = 255;
var pa:int = na & oa;
var qa:int = ma - pa;
e7:int = qa;
label B_a:
var ra:int = e7:int;
return ra;
}
export function check_flag():int {
var a:int = 0;
var b:int = 1072;
var c:int = 1024;
var d:int = strcmp(c, b);
var e:int = d;
var f:int = a;
var g:int = e != f;
var h:int = -1;
var i:int = g ^ h;
var j:int = 1;
var k:int = i & j;
return k;
}
function copy(a:int, b:int) {
var c:int = g_a;
var d:int = 16;
var e:int_ptr = c - d;
e3 = a;
e2 = b;
var f:int = e3;
if (eqz(f)) goto B_a;
var g:int = e3;
var h:int = 8;
var i:int = g ^ h;
e3 = i;
label B_a:
var j:int = e3;
var k:byte_ptr = e2;
k1072 = j;
}
読め無さそうt6o_o6t.icon
WebAssemblyのReversingはどうすれば良い?
WebAssembly
読めないと思い込んでいたt6o_o6t.icon
check_flagを1にできればよいので、check_flagの内容を把握できれば良い
b = 1024というのは、strcmpにbが渡されていることから、文字列のアドレス