python 學習五四三
'0x' 與 ’\x’的關係?
在這之前得先了解 4 個相互轉換的函式: chr() / ord() = char to unicode number / unicode number to char int() / hex() = convert to a base of 10 / convert to a base of 16
1: In [1]: ord('A') 2: Out[1]: 65 3: In [2]: chr(65) 4: Out[2]: 'A' 5: In [3]: hex(65) 6: Out[3]: '0x41' 7: In [4]: int('0x41', 16) 8: Out[4]: 65 9: In [9]: '\x41' 10: Out[9]: 'A' 11: In [10]: '0x41' 12: Out[10]: '0x41' 13: In [11]: chr(int('0x41',16)) 14: Out[11]: 'A'
如何執行一段 string-based statements
1: py_loop_stmt = """ 2: def py_hello(): 3: for i in xrange(10): 4: print i, 5: print 6: print "have a nice day!" 7: """ 8: co = compile(py_loop_stmt, '', 'exec') 9: exec(co) 10: py_hello() 11: 0 1 2 3 4 5 6 7 8 9 12: have a nice day! 13: #或者是 14: exec('exec(co);import __main__;getattr(__main__, "%s")()' % co.co_names[0]) 15: 0 1 2 3 4 5 6 7 8 9 16: have a nice day!
compile() 與 exec() 還真是挺邪惡的東西啊。
如何在任意 function 裏頭取得其命名
How to get the function name inside the function?python 似乎沒有直接取得的方式. 不過在 libsys 裏頭 _gertframe 用以取得 frame object, 然後取得它參數的 f_code.co_name. 與取得 code object 方式類似.
1: import sys 2: def myDaring(): 3: print "call me:", sys._getframe().f_code.co_name 4: myDaring() 5: call me: myDaring
原先的發想是(1)想在 python code 裡面執行一段 bytecodes;(2)動態修改這段 bytecode 的值. [就是injection] 這裡涉及 python interpreter 的運作原理. 好在這東西早些時間就已經有人寫好, 挺容易理解的.
1: def ggprint(func, text): 2: print '*'*5, func, '*'*5 3: print text 4: print '*' *30 5: def dumpArgsCodeobj(codeobj): 6: params = [] 7: for x in dir(codeobj): 8: if x.startswith('co'): 9: params.append( x + ':' + str(getattr(codeobj, x)) ) 10: ggprint(sys._getframe().f_code.co_name, '\n'.join(params)) 11: dumpArgsCodeobj(py_hello.__code__) 12: ***** dumpArgsCodeobj ***** 13: co_argcount:0 14: co_cellvars:() 15: co_code:x td � D] 16: WHd GHdS 17: co_consts:(None, 10, 'have a nice day!') 18: co_filename: 19: co_firstlineno:2 20: co_flags:67 21: co_freevars:() 22: co_lnotab: 23: co_name:py_hello 24: co_names:('xrange',) 25: co_nlocals:1 26: co_stacksize:2 27: co_varnames:('i',) 28: ******************************
其中值得注意的是 co_code, co_consts, co_names 這幾個參數. 可以利用 dis 這個 module 反編譯了解它的邏輯.
1: import dis 2: dis.disassemble(py_hello.__code__) 3: 3 0 SETUP_LOOP 24 (to 27) 4: 3 LOAD_GLOBAL 0 (xrange) 5: 6 LOAD_CONST 1 (10) 6: 9 CALL_FUNCTION 1 7: 12 GET_ITER 8: >> 13 FOR_ITER 10 (to 26) 9: 16 STORE_FAST 0 (i) 10: 4 19 LOAD_FAST 0 (i) 11: 22 PRINT_ITEM 12: 23 JUMP_ABSOLUTE 13 13: >> 26 POP_BLOCK 14: 5 >> 27 PRINT_NEWLINE 15: 6 28 LOAD_CONST 2 ('have a nice day!') 16: 31 PRINT_ITEM 17: 32 PRINT_NEWLINE 18: 33 LOAD_CONST 0 (None) 19: 36 RETURN_VALUE
可以利用一個叫 bytecodehacks 的一個開源工具去對 codeobject去做修改, 像是引入外部的參數到內部, 修改 const的值, 以及loop的邏輯等等. 不過這裡我原先的初衷有很大的不同: 我把 bytecodes 搞混了. 或者說我先前想知道別人寫的.py 裏頭的 bytecodes 是什麼意思, 但事實上那段是compiled bytecodes, 是machine code了. 這讓我又多了兩個問題:(1)倘若想在 .py 執行一段 c/c++ 的 copmiled bytecode; 或者(2)想要動態存取其他程序的變數, 又該怎麼去實現呢?
1: 關鍵字是 ctypes, kernel32.dll, WriteProcessMemory, ReadProcessMemory 2: import ctypes 3: kernel32 = ctypes.WinDLL('kernel32.dll') 4: def get_handle(pid): 5: PROCESS_VM_OPERATION = 0x0008 6: PROCESS_VM_READ = 0x0010 7: PROCESS_VM_WRITE = 0x0020 8: PROCESS_SET_INFORMATION = 0x0200 9: PROCESS_QUERY_INFORMATION = 0x0400 10: PROCESS_INFO_ALL = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION 11: PROCESS_VM_ALL = PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE 12: res = kernel32.OpenProcess(PROCESS_INFO_ALL | PROCESS_VM_ALL, False, pid) 13: print "Returning handle %d" % res 14: return res
就先這樣吧, 寫了一整天腦袋好暈. 一個お盆休み居然感冒, 真的很衰小...Orz
參考連結:MSDN, Bytecodehacks, Stackoverflow, source code beautifier
Comments
Post a Comment