Open WannaSS1eep opened 1 month ago
__int64 sub_2B3C()
{
__int64 v0; // rax
int i; // [rsp+0h] [rbp-10h]
signed int j; // [rsp+4h] [rbp-Ch]
__int64 t; // [rsp+8h] [rbp-8h]
sub_1F3B(); // initialize components of code object
for ( i = 0; i <= 2; ++i )
sub_1DBC(); // create code object and calls `emulate`
if ( !(qword_66F0 ^ 0xFDF61CB53A00DAA8LL | qword_66E8 ^ 0x273AED9AEFD29A3CLL | qword_66E0 ^ 0x7AB48E39E26BE2A7LL | qword_66F8 ^ 0xFC796489FC8864EELL) )
{
t = GetAttrString(module_main, t_encoded); // PyObject_GetAttrString(module_main, "t")
for ( j = 0; (unsigned int)j <= 0x1D; ++j )
{
v0 = PyLong_FromUnsignedLongLong(byte_6410[j]);
PyList_SetItem(t, j, v0);
}
}
return sub_13CF(&Py_NoneStruct);
}
void __fastcall sub_1DBC()
{
v15 = PyBytes_FromString(&unk_3011);
v0 = sub_1491(&unk_3011);
v1 = sub_1491(&unk_3011);
v2 = PyTuple_New(0LL);
v3 = PyTuple_New(0LL);
v4 = PyTuple_New(0LL);
v14 = qword_6760[round];
v13 = qword_6740[round];
v5 = PyBytes_FromStringAndSize(qword_6440[round], dword_6430[round]);
v6 = PyCode_New(0LL, 0LL, 0LL, 16LL, 0LL, v5, v13, v14, v4, v3, v2, v1, v0, 0LL, v15);
v11 = PyTuple_Pack(1LL, v6, v7, v8, v9, v10, v12, v13, v14, v15, v16, v6, v17, v18);
PyObject_CallObject(qword_6788, v11);
++round; // round (dword_6790) starts from 1 because `PyInit_checker` increments it
}
Based on Python3.10 PyCode_New
API documentation, we can construct like this:
v6 = PyCode_New(
argcount=0LL,
kwonlyargcount=0LL,
nlocals=0LL,
stacksize=16LL,
flags=0LL,
code=v5, // PyBytes_FromStringAndSize(qword_6440[round], dword_6430[round]) -> qword_6440 : bytecodes, dword_6430 : size of bytecode
consts=v13, // qword_6740[round] -> consts
names=v14, // qword_6760[round] -> names
varnames=v4, // PyTuple_New(0LL)
freevars=v3, // PyTuple_New(0LL)
cellvars=v2, // PyTuple_New(0LL)
filename=v1, // PyUnicode_FromString("")
name=v0, // PyUnicode_FromString("")
firstlineno=0LL,
lnotab=v15 // PyBytes_FromString("")
);
.data:0000000000006430 dword_6430 dd 0, 0B14h, 3C4h, 424h
You can extract bytecodes with size dword_6430[round]
from qword_6440[round]
void sub_1F3B()
{
...
v1 = PyLong_FromUnsignedLongLong(255LL);
v2 = PyLong_FromUnsignedLongLong(0LL);
v3 = PyLong_FromUnsignedLongLong(6LL);
v4 = PyLong_FromUnsignedLongLong(5LL);
v5 = PyLong_FromUnsignedLongLong(4LL);
v36 = v67;
qword_6748 = PyTuple_Pack(39LL, &Py_NoneStruct, v5, v4, v3, v2, v1, v0, v55, v56, v57, v58, v59, v60);
...
qword_6750 = PyTuple_Pack(50LL, &Py_NoneStruct, v11, v10, v9, v8, v7, v6, v40, v43, v46, v49, v51, v53);
...
qword_6758 = PyTuple_Pack(12LL, &Py_NoneStruct, v17, v61, v62, v63, v16, v15, v14, v13, v12, v65, v68, v36);
...
qword_6768 = PyTuple_Pack(7LL, v23, v22, v21, v20, v69, v19, v18, v37, v40, v43, v46, v49, v51);
...
qword_6770 = PyTuple_Pack(9LL, v29, v28, v64, v66, v70, v27, v26, v25, v24, v38, v41, v44, v47);
...
result = PyTuple_Pack(5LL, v34, v33, v32, v31, v30, v39, v42, v45, v48, v50, v52, v53, v54);
qword_6778 = result;
}
Based on Python3.10 PyTuple_Pack
API documentation, first argument of PyTuple_Pack
is size of tuple.
qword_6748
~qword_6758
is qword_6740[round]
(round
(dword_6790) starts from 1
because PyInit_checker
increments it)
And qword_6768
~qword_6778
is qword_6760[round]
.
So, you can get all co_code
, co_consts
and co_names
as I wrote in bytecode_to_pyc.py
.
thxxxxxx it help a lot
---Original--- From: "Hyeongcheol @.> Date: Mon, Jul 29, 2024 23:35 PM To: @.>; Cc: @.**@.>; Subject: Re: [zzre/DeadSecCTF-2024-FlagChecker] Need Help (Issue #1)
sub_2B3C (checker.check)
__int64 sub_2B3C() { int64 v0; // rax int i; // [rsp+0h] [rbp-10h] signed int j; // [rsp+4h] [rbp-Ch] int64 t; // [rsp+8h] [rbp-8h] sub_1F3B(); // initialize components of code object for ( i = 0; i <= 2; ++i ) sub_1DBC(); // create code object and calls emulate
if ( !(qword_66F0 ^ 0xFDF61CB53A00DAA8LL | qword_66E8 ^ 0x273AED9AEFD29A3CLL | qword_66E0 ^ 0x7AB48E39E26BE2A7LL | qword_66F8 ^ 0xFC796489FC8864EELL) ) { t = GetAttrString(module_main, t_encoded); // PyObject_GetAttrString(module_main, "t") for ( j = 0; (unsigned int)j <= 0x1D; ++j ) { v0 = PyLong_FromUnsignedLongLong(byte_6410[j]); PyList_SetItem(t, j, v0); } } return sub_13CF(&Py_NoneStruct); }
sub_1DBC void __fastcall sub_1DBC() { v15 = PyBytes_FromString(&unk_3011); v0 = sub_1491(&unk_3011); v1 = sub_1491(&unk_3011); v2 = PyTuple_New(0LL); v3 = PyTuple_New(0LL); v4 = PyTuple_New(0LL); v14 = qword_6760[round]; v13 = qword_6740[round]; v5 = PyBytes_FromStringAndSize(qword_6440[round], dword_6430[round]); v6 = PyCode_New(0LL, 0LL, 0LL, 16LL, 0LL, v5, v13, v14, v4, v3, v2, v1, v0, 0LL, v15); v11 = PyTuple_Pack(1LL, v6, v7, v8, v9, v10, v12, v13, v14, v15, v16, v6, v17, v18); PyObject_CallObject(qword_6788, v11); ++round; // round (dword_6790) starts from 1 because PyInit }
Based on Python3.10 PyCode_New API documentation, we can construct like this:
v6 = PyCode_New( argcount=0LL, kwonlyargcount=0LL, nlocals=0LL, stacksize=16LL, flags=0LL, code=v5, // PyBytes_FromStringAndSize(qword_6440[round], dword_6430[round]) -> qword_6440 : bytecodes, dword_6430 : size of bytecode consts=v13, // qword_6740[round] -> consts names=v14, // qword_6760[round] -> names varnames=v4, // PyTuple_New(0LL) freevars=v3, // PyTuple_New(0LL) cellvars=v2, // PyTuple_New(0LL) filename=v1, // PyUnicode_FromString("") name=v0, // PyUnicode_FromString("") firstlineno=0LL, lnotab=v15 // PyBytes_FromString("") );
.data:0000000000006430 dword_6430 dd 0, 0B14h, 3C4h, 424h
You can extract bytecodes with size dword_6430[round] from qword_6440[round]
sub_1F3B void sub_1F3B() { ... v1 = PyLong_FromUnsignedLongLong(255LL); v2 = PyLong_FromUnsignedLongLong(0LL); v3 = PyLong_FromUnsignedLongLong(6LL); v4 = PyLong_FromUnsignedLongLong(5LL); v5 = PyLong_FromUnsignedLongLong(4LL); v36 = v67; qword_6748 = PyTuple_Pack(39LL, &Py_NoneStruct, v5, v4, v3, v2, v1, v0, v55, v56, v57, v58, v59, v60); ... qword_6750 = PyTuple_Pack(50LL, &Py_NoneStruct, v11, v10, v9, v8, v7, v6, v40, v43, v46, v49, v51, v53); ... qword_6758 = PyTuple_Pack(12LL, &Py_NoneStruct, v17, v61, v62, v63, v16, v15, v14, v13, v12, v65, v68, v36); ... qword_6768 = PyTuple_Pack(7LL, v23, v22, v21, v20, v69, v19, v18, v37, v40, v43, v46, v49, v51); ... qword_6770 = PyTuple_Pack(9LL, v29, v28, v64, v66, v70, v27, v26, v25, v24, v38, v41, v44, v47); ... result = PyTuple_Pack(5LL, v34, v33, v32, v31, v30, v39, v42, v45, v48, v50, v52, v53, v54); qword_6778 = result; }
Based on Python3.10 PyTuple_Pack API documentation, first argument of PyTuple_Pack is size of tuple.
qword_6748~qword_6758 is qword_6740[round] (round(dword_6790) starts from 1 because PyInit_checker increments it)
And qword_6768~qword_6778 is qword_6760[round].
So, you can get all co_code, co_consts and co_names as I wrote in bytecode_to_pyc.py.
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>
i wonder if you can describe bytecode_to_pyc.py with more detail?I am confused by why you write script like that