<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
由於展示最基本最簡單的實現,使用演演算法加密就沒用複雜的。如果使用比較複雜的加密,首先你在C++
程式碼層面和組合層面要有配套的程式碼,C++
負責加密,組合負責自我解密,否則你加密完了,結果加密後的PE
檔案自己又解密不了,這就很尷尬。
在所有加密演演算法,互斥或加密是最簡單的,也是最好是實現的。我們來介紹互斥或加密的原理。
已知兩個數A
和B
,如果A xor B = C
,則C xor B = A
,其中xor
表示互斥或運運算元。如果不理解,這個是入門程式設計的最基本的知識,請自行補缺,這裡我就不嘮叨了。
下面是我們實現互斥或加密的相關函數:
// GNU AFFERO GENERAL PUBLIC LICENSE //Version 3, 19 November 2007 //Copyright(C) 2007 Free Software Foundation, Inc. //Everyone is permitted to copyand distribute verbatim copies //of this license document, but changing it is not allowed. // Author : WingSummer (寂靜的羽夏) //Warning: You can not use it for any commerical use,except you get // my AUTHORIZED FORM ME!This project is used for tutorial to teach // the beginners what is the PE structure and how the packer of the PE files works. BOOL CWingProtect::XORCodeSection(BOOL NeedReloc, BOOL FakeCode) { using namespace asmjit; if (_lasterror != ParserError::Success) return FALSE; auto filesize = peinfo.FileSize.QuadPart; CodeHolder holder; /// <summary> /// PointerToRawData /// </summary> auto p = peinfo.PCodeSection->PointerToRawData; /// <summary> /// SizeOfRawData /// </summary> auto sizecode = peinfo.PCodeSection->SizeOfRawData; auto repeat = sizecode; BYTE* shellcode; INT3264 ccount; if (is64bit) { Environment env(Arch::kX64); holder.init(env); x86::Assembler a(&holder); Label loop = a.newLabel(); x86::Mem mem; mem.setSegment(x86::gs); mem.setOffset(0x60); //生成加密 shellcode,此處的 rax = ImageBase a.push(x86::rcx); a.push(x86::rdi); //xor 解密 a.mov(x86::rax, mem); a.mov(x86::rax, x86::qword_ptr(x86::rax, 0x10)); a.mov(x86::rdi, x86::rax); a.add(x86::rdi, peinfo.PCodeSection->VirtualAddress); a.mov(x86::rcx, repeat); a.bind(loop); if (FakeCode) FakeProtect(a); a.xor_(x86::byte_ptr(x86::rdi), 0x55); a.inc(x86::rdi); a.dec(x86::rcx); a.test(x86::rcx, x86::rcx); a.jnz(loop); //確保此時 rax 或 eax 存放的是 ImageBase ,否則是未定義行為 if (NeedReloc) RelocationSection(a); a.pop(x86::rdi); a.pop(x86::rcx); a.ret(); shellcode = a.bufferData(); ccount = holder.codeSize(); } else { Environment env(Arch::kX86); holder.init(env); x86::Assembler a(&holder); Label loop = a.newLabel(); x86::Mem mem; mem.setSegment(x86::fs); mem.setOffset(0x30); //生成加密 shellcode a.push(x86::ecx); a.push(x86::edi); a.mov(x86::eax, mem); a.mov(x86::eax, x86::dword_ptr(x86::eax, 0x8)); a.mov(x86::edi, x86::eax); a.add(x86::edi, peinfo.PCodeSection->VirtualAddress); a.mov(x86::ecx, repeat); a.bind(loop); if (FakeCode) FakeProtect(a); a.xor_(x86::byte_ptr(x86::edi), 0x55); a.inc(x86::edi); a.dec(x86::ecx); a.test(x86::ecx, x86::ecx); a.jnz(loop); //確保此時 rax 或 eax 存放的是 ImageBase ,否則是未定義行為 if (NeedReloc) RelocationSection(a); a.pop(x86::edi); a.pop(x86::ecx); a.ret(); shellcode = a.bufferData(); ccount = holder.codeSize(); } //互斥或加密 auto se = (BYTE*)b; for (UINT i = 0; i < repeat; i++) { se[i] ^= (BYTE)0x55; } //加密完畢,寫 Shellcode encryptInfo.XORDecodeShellCode = (UINT)peinfo.PointerOfWingSeciton; auto ws = GetPointerByOffset(peinfo.WingSecitonBuffer, peinfo.PointerOfWingSeciton); memcpy_s(ws, ccount, shellcode, ccount); peinfo.PointerOfWingSeciton += ccount; if (!NeedReloc) { auto tmp = (PIMAGE_SECTION_HEADER)TranModPEWapper(peinfo.PCodeSection); tmp->Characteristics |= IMAGE_SCN_MEM_WRITE; } return TRUE; }
在C++程式碼層面,加密程式碼區內容相關的程式碼如下:
//互斥或加密 auto se = (BYTE*)b; for (UINT i = 0; i < repeat; i++) { se[i] ^= (BYTE)0x55; }
^
表示互斥或運運算元,在組合層面,以64位元為例,實現如下所示:
a.mov(x86::rax, mem); a.mov(x86::rax, x86::qword_ptr(x86::rax, 0x10)); a.mov(x86::rdi, x86::rax); a.add(x86::rdi, peinfo.PCodeSection->VirtualAddress); a.mov(x86::rcx, repeat); a.bind(loop); if (FakeCode) FakeProtect(a); a.xor_(x86::byte_ptr(x86::rdi), 0x55); a.inc(x86::rdi); a.dec(x86::rcx); a.test(x86::rcx, x86::rcx); a.jnz(loop);
可以看出來組合寫起來比寫C++
程式碼麻煩多了,裡面有一些程式碼可能有一些其他的考慮,我們這裡說一下:
首先是FakeProtect
,這個就是生成花指令,這裡不多說,後面在介紹。還有一個函數比較注意RelocationSection
,這個函數是用來生成做重定位的組合程式碼的,為什麼要有這個函數呢?
比如我只有互斥或加密,我們是在寫死的層面進行的加密,PE
被載入進入的時候如果基址不和預想的那樣,就會查是否有重定位表,如果有的話就解析並修復。但是,我們的程式碼是加密的,而重定位表沒做修改,它就會錯誤的把被加密的寫死進行重定位,這個是不能夠允許的。所以我們需要摧毀重定位表,可以看到CWingProtect::Proctect裡面有一個函數DestoryRelocation
,這個作用就是用來銷燬它的,不讓PE
載入器幫我們做重定位。
綜上所述,我們需要自己做重定位,我們需要在組合層面來實現重定位表的修復,我們來看一下相關程式碼:
// // GNU AFFERO GENERAL PUBLIC LICENSE //Version 3, 19 November 2007 // //Copyright(C) 2007 Free Software Foundation, Inc. //Everyone is permitted to copyand distribute verbatim copies //of this license document, but changing it is not allowed. // Author : WingSummer (寂靜的羽夏) // //Warning: You can not use it for any commerical use,except you get // my AUTHORIZED FORM ME!This project is used for tutorial to teach // the beginners what is the PE structure and how the packer of the PE files works. void CWingProtect::RelocationSection(asmjit::x86::Assembler& a) { using namespace asmjit; Label loop_xor = a.newLabel(); Label loop_reloc = a.newLabel(); Label loop_rt = a.newLabel(); Label endproc = a.newLabel(); auto rdd = peinfo.PDataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; if (is64bit) { a.nop(); a.push(x86::rdi); a.push(x86::rcx); a.push(x86::rsi); //徵用 rsi a.mov(x86::rsi, rdd.VirtualAddress); //重定位表基址 a.add(x86::rsi, x86::rax); a.push(x86::rdx); //徵用 rdx a.push(x86::r10); a.mov(x86::r10, peinfo.ImageBase); //PE 載入後,該值會被重定位,只能寫死 a.sub(x86::r10, x86::rax); a.jz(endproc); a.bind(loop_rt); a.mov(x86::edi, x86::dword_ptr(x86::rsi)); //偏移基址地址 a.add(x86::rdi, x86::rax); //此時 rdi 為載入到記憶體的虛擬基址地址 //計數 a.mov(x86::ecx, x86::dword_ptr(x86::rsi, 4)); a.sub(x86::ecx, 8); a.shr(x86::ecx, 1); //此時為重定位表的真實專案個數 a.add(x86::rsi, 8); //將指標指向該索引下的第一個重定位專案 a.bind(loop_reloc); a.dec(x86::rcx); a.mov(x86::dx, x86::word_ptr(x86::rsi, x86::rcx, 1)); a.test(x86::dx, 0xF000); a.jz(loop_reloc); //contine; a.and_(x86::edx, 0xFFF); a.add(x86::rdx, x86::rdi); a.sub(x86::qword_ptr(x86::rdx), x86::r10); //修正 a.cmp(x86::rcx, 0); a.ja(loop_reloc); a.sub(x86::rsi, 8); //重新指向表頭 a.mov(x86::edx, x86::dword_ptr(x86::rsi, 4)); a.add(x86::rsi, x86::rdx); //指向下一個 a.mov(x86::edx, x86::dword_ptr(x86::rsi)); a.test(x86::edx, x86::edx); a.jnz(loop_rt); a.bind(endproc); a.pop(x86::r10); a.pop(x86::rdx); a.pop(x86::rsi); //釋放 rsi 自由身 a.pop(x86::rcx); a.pop(x86::rdi); } else { a.push(x86::edi); a.push(x86::ecx); a.push(x86::esi); //徵用 rsi a.mov(x86::esi, rdd.VirtualAddress); //重定位表基址 a.add(x86::esi, x86::eax); a.push(x86::edx); //徵用 edx a.push((DWORD32)peinfo.ImageBase); //x86暫存器沒那麼多,只能自己維護一個區域性變數 a.sub(x86::dword_ptr(x86::esp), x86::rax); a.jz(endproc); a.bind(loop_rt); a.mov(x86::edi, x86::dword_ptr(x86::esi)); //偏移基址地址 a.add(x86::edi, x86::eax); //此時 rdi 為載入到記憶體的虛擬基址地址 //計數 a.mov(x86::ecx, x86::dword_ptr(x86::esi, 4)); a.sub(x86::ecx, 8); a.shr(x86::ecx, 1); //此時為重定位表的真實專案個數 a.add(x86::esi, 8); //將指標指向該索引下的第一個重定位專案 a.bind(loop_reloc); a.dec(x86::ecx); a.mov(x86::dx, x86::word_ptr(x86::rsi, x86::ecx, 1)); a.test(x86::dx, 0xF000); a.jz(loop_reloc); //contine; a.and_(x86::edx, 0xFFF); a.add(x86::edx, x86::edi); a.push(x86::eax); //使用區域性變數 a.mov(x86::eax, x86::dword_ptr(x86::esp, 4)); //注意被 push 了一個,所以加個偏移 a.sub(x86::dword_ptr(x86::edx), x86::eax); //修正 a.pop(x86::eax); a.cmp(x86::ecx, 0); a.ja(loop_reloc); a.sub(x86::esi, 8); //重新指向表頭 a.mov(x86::edx, x86::dword_ptr(x86::esi, 4)); a.add(x86::esi, x86::rdx); //指向下一個 a.mov(x86::edx, x86::dword_ptr(x86::esi)); a.test(x86::edx, x86::edx); a.jnz(loop_rt); a.bind(endproc); a.add(x86::esp, 4); //釋放區域性變數 a.pop(x86::edx); a.pop(x86::esi); //釋放 rsi 自由身 a.pop(x86::ecx); a.pop(x86::edi); } //將所有的節全部改為可寫 auto length = peinfo.NumberOfSections; for (UINT i = 0; i < length; i++) { ((PIMAGE_SECTION_HEADER)TranModPEWapper(&peinfo.PSectionHeaders[i])) ->Characteristics |= IMAGE_SCN_MEM_WRITE; } }
對於以上程式碼你可能有一些疑問,我這裡說一下:
為什麼呼叫a.nop()
來生成沒有用的指令,這個是我用來方便偵錯我生成的ShellCode
用的,否則會生成一大坨組合到後來自己也不清楚自己在偵錯啥的,通過這個nop
我就可以清楚的直到我到那裡了,如果出錯的話我也方便進行定位。
此函數最後生成完ShellCode
之後又將所有的節全部改為可寫屬性,這是為什麼呢?因為線性記憶體是有屬性的,如果我沒有將其設定可寫,如果它是唯讀記憶體,如果我對它做重定位修改的話,就會報記憶體存取錯誤,導致程式崩潰。
怎麼用組合來解析重定位表,這裡就不贅述了。
在編寫ShellCode
程式碼的時候,請一定保證如下原則,避免一些麻煩,否則會出現出乎意料的錯誤:
以上就是使用c++實現互斥或加密的程式碼範例的詳細內容,更多關於c++互斥或加密範例的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45