| 240 | python_function_64_bits = {} |
| 241 | |
| 242 | def generate_python_exec_shellcode_64(target, PyDll): |
| 243 | pymodule = [mod for mod in target.peb.modules if mod.name == PyDll][0] |
| 244 | base = pymodule.baseaddr |
| 245 | if not python_function_64_bits: |
| 246 | Py_exports = pymodule.pe.exports |
| 247 | python_function_64_bits["PyEval_InitThreads"] = Py_exports["PyEval_InitThreads"] - base |
| 248 | python_function_64_bits["Py_IsInitialized"] = Py_exports["Py_IsInitialized"] - base |
| 249 | python_function_64_bits["PyGILState_Release"] = Py_exports["PyGILState_Release"] - base |
| 250 | python_function_64_bits["PyGILState_Ensure"] = Py_exports["PyGILState_Ensure"] - base |
| 251 | python_function_64_bits["PyEval_SaveThread"] = Py_exports["PyEval_SaveThread"] - base |
| 252 | python_function_64_bits["Py_Initialize"] = Py_exports["Py_Initialize"] - base |
| 253 | python_function_64_bits["PyRun_SimpleString"] = Py_exports["PyRun_SimpleString"] - base |
| 254 | Py_exports = python_function_64_bits |
| 255 | PyEval_InitThreads = Py_exports["PyEval_InitThreads"] + base |
| 256 | Py_IsInitialized = Py_exports["Py_IsInitialized"] + base |
| 257 | PyGILState_Release = Py_exports["PyGILState_Release"] + base |
| 258 | PyGILState_Ensure = Py_exports["PyGILState_Ensure"] + base |
| 259 | PyEval_SaveThread = Py_exports["PyEval_SaveThread"] + base |
| 260 | Py_Initialize = Py_exports["Py_Initialize"] + base |
| 261 | PyRun_SimpleString = Py_exports["PyRun_SimpleString"] + base |
| 262 | |
| 263 | Reserve_space_for_call = x64.MultipleInstr([x64.Push('RDI')] * 4) |
| 264 | Clean_space_for_call = x64.MultipleInstr([x64.Pop('RDI')] * 4) |
| 265 | code = x64.MultipleInstr() |
| 266 | # Do stack alignement |
| 267 | code += x64.Push('RCX') |
| 268 | code += Reserve_space_for_call |
| 269 | code += x64.Mov('RAX', Py_IsInitialized) |
| 270 | code += x64.Call('RAX') |
| 271 | code += x64.Mov("RDI", "RAX") |
| 272 | code += x64.Cmp("RAX", 0) |
| 273 | code += x64.Jnz(":DO_ENSURE") |
| 274 | code += x64.Mov('RAX', Py_Initialize) |
| 275 | code += x64.Call('RAX') |
| 276 | # https://docs.python.org/3/c-api/init.html#c.PyEval_InitThreads |
| 277 | code += x64.Mov('RAX', PyEval_InitThreads) |
| 278 | code += x64.Call('RAX') |
| 279 | code += x64.Label(":DO_ENSURE") |
| 280 | code += x64.Mov('RAX', PyGILState_Ensure) |
| 281 | code += x64.Call('RAX') |
| 282 | code += x64.Mov('R15', 'RAX') |
| 283 | code += x64.Mov("RCX", x64.mem("[RSP + 0x20]")) |
| 284 | code += x64.Mov('RAX', PyRun_SimpleString) |
| 285 | code += x64.Call('RAX') |
| 286 | code += x64.Mov('RCX', 'R15') |
| 287 | code += x64.Mov('R15', 'RAX') |
| 288 | code += x64.Mov('RAX', PyGILState_Release) |
| 289 | code += x64.Call('RAX') |
| 290 | code += x64.Cmp("RDI", 0) |
| 291 | code += x64.Jnz(":RETURN") |
| 292 | # If PyEval_InitThreads was called (init done in this thread) |
| 293 | # We must release the GIL |
| 294 | code += x64.Mov('RAX', PyEval_SaveThread) |
| 295 | code += x64.Call('RAX') |
| 296 | code += x64.Label(":RETURN") |
| 297 | code += Clean_space_for_call |
| 298 | # Remove stack alignement |
| 299 | code += x64.Pop('RCX') |