In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)05/31 Report--
This article mainly introduces "how to use C++ to achieve XOR encryption". In daily operation, I believe many people have doubts about how to use C++ to achieve XOR encryption. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful to answer the doubts about "how to use C++ to achieve XOR encryption". Next, please follow the editor to study!
Encryption principle
By showing the most basic and simplest implementation, it is not complicated to use algorithmic encryption. If you use more complex encryption, first of all, you should have matching code at the C++ code level and assembly level, C++ is responsible for encryption, assembly is responsible for self-decryption, otherwise you are encrypted, the encrypted PE file can not be decrypted by yourself, this is very embarrassing.
Of all encryption algorithms, XOR encryption is the simplest and best implemented. Let's introduce the principle of XOR encryption.
Two numbers An and B are known, and if A xor B = C, then C xor B = A, where xor represents the XOR operator. If you do not understand, this is the most basic knowledge of entry programming, please fill the gap by yourself, I will not nag here.
Implementation of XOR encryption
Here are the functions we use to implement XOR encryption:
/ / 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 (Silent Yuxia) / / 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; / PointerToRawData / auto p = peinfo.PCodeSection- > PointerToRawData / SizeOfRawData / 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); / / generate encrypted shellcode, where rax = ImageBase a.push (x86::rcx); a.push (x86::rdi); / / xor decrypt 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.xorx86::byte_ptr (x86::rdi), 0x55); a.inc (x86::rdi); a.dec (x86::rcx); a.test (x86::rcx, x86::rcx) A.jnz (loop); / / make sure that the rax or eax stores ImageBase, otherwise the undefined behavior 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); / / generate encrypted 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) / / make sure that ImageBase is stored in rax or eax, otherwise undefined behavior if (NeedReloc) RelocationSection (a); a.pop (x86::edi); a.pop (x86::ecx); a.ret (); shellcode = a.bufferData (); ccount = holder.codeSize ();} / XOR encryption 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;}
At the code level of C++, the codes related to the content of the encrypted code area are as follows:
/ / XOR encryption 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.xorx86::byte_ptr (x86::rdi), 0x55); a.inc (x86::rdi); a.dec (x86::rcx); a.test (x86::rcx, x86::rcx); a.jnz (loop)
You can see that assembler is much more troublesome than writing C++ code, and there are some code that may have some other considerations. Let's talk about it here:
The first is FakeProtect, which is to generate flower instructions, which is not said much here, but will be introduced later. There is also a function that pays more attention to RelocationSection. This function is used to generate assembly code for relocation. Why should there be this function?
For example, I only have XOR encryption, and we encrypt it at the hard-coded level. If the base address is not as expected when the PE is loaded, it will check if there is a relocation table, and if so, it will be parsed and repaired. However, our code is encrypted, and if the relocation table is not modified, it will mistakenly relocate the encrypted hard code, which is not allowed. So we need to destroy the relocation table, and we can see that there is a function DestoryRelocation in CWingProtect::Proctect, which is used to destroy it and not to let the PE loader do the relocation for us.
To sum up, we need to do our own relocation, and we need to fix the relocation table at the assembly level. Let's take a look at the relevant code:
/ 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 (Silent Yuxia) / 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.PDataDirection [image _ DIRECTORY_ENTRY_BASERELOC] If (is64bit) {a.nop (); a.push (x86::rdi); a.push (x86::rcx); a.push (x86::rsi); / / requisition rsi a.mov (x86::rsi, rdd.VirtualAddress); / / relocation table base address a.add (x86::rsi, x86::rax); a.push (x86::rdx) / / requisitioned rdx a.push (x86::r10); a.mov (x86::r10, peinfo.ImageBase); / / after PE is loaded, the value will be relocated and can only be written as a.sub (x86::r10, x86::rax); a.jz (endproc); a.bind (loop_rt); a.mov (x86::edi, x86::dword_ptr (x86::rsi)) / / offset base address a.add (x86::rdi, x86::rax); / / rdi is the virtual base address loaded into memory / / count a.mov (x86::ecx, x86::dword_ptr (x86::rsi, 4)); a.sub (x86::ecx, 8); a.shr (x86::ecx, 1) / / the real number of items in the relocation table a.add (x86::rsi, 8) at this time; / / point the pointer to the first relocation item under the index, 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); / / modified a.cmp (x86::rcx, 0) A.ja (loop_reloc); a.sub (x86::rsi, 8); / / repoint to the header a.mov (x86::edx, x86::dword_ptr (x86::rsi, 4)); a.add (x86::rsi, x86::rdx); / / to the next 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); / / release rsi free a.pop (x86::rcx); a.pop (x86::rdi) } else {a.push (x86::edi); a.push (x86::ecx); a.push (x86::esi); / / requisition rsi a.mov (x86::esi, rdd.VirtualAddress); / / relocation table base address a.add (x86::esi, x86::eax); a.push (x86::edx) / / requisitioned edx a.push ((DWORD32) peinfo.ImageBase); / / not so many x86 registers, so you can only maintain a local variable 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)) / / offset base address a.add (x86::edi, x86::eax); / / rdi is the virtual base address loaded into memory / / count a.mov (x86::ecx, x86::dword_ptr (x86::esi, 4)); a.sub (x86::ecx, 8); a.shr (x86::ecx, 1) / / the real number of items in the relocation table a.add (x86::esi, 8) at this time; / / point the pointer to the first relocation item under the index, 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.andn _ (x86::edx, 0xFFF); a.add (x86::edx, x86::edi); a.push (x86::eax); / / use the local variable a.mov (x86::eax, x86::dword_ptr (x86::esp, 4)) / / notice that one has been push, so add an offset a.sub (x86::dword_ptr (x86::edx), x86::eax); / / modify a.pop (x86::eax); a.cmp (x86::ecx, 0); a.ja (loop_reloc); a.sub (x86::esi, 8) / / repoint to the header a.mov (x86::edx, x86::dword_ptr (x86::esi, 4)); a.add (x86::esi, x86::rdx); / / to the next 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); / / release local variables a.pop (x86::edx); a.pop (x86::esi); / / release rsi free a.pop (x86::ecx); a.pop (x86::edi);} / / change all sections to writable auto length = peinfo.NumberOfSections For (UINT I = 0; I
< length; i++) { ((PIMAGE_SECTION_HEADER)TranModPEWapper(&peinfo.PSectionHeaders[i])) ->Characteristics | = IMAGE_SCN_MEM_WRITE;}}
You may have some questions about the above code, let me say something here:
Why call a.nop () to generate useless instructions? this is what I use to debug my generated ShellCode, otherwise it will generate a large pile of assembly so that I don't know what I'm debugging later. Through this nop, I can make it clear until I get there, and it's easy for me to locate if something goes wrong.
Why is it that this function finally generates ShellCode and changes all sections to writable properties? Because linear memory has properties, if I don't make it writable, if it is read-only memory, if I relocate it, it will report a memory access error and cause the program to crash.
How to use assembly to parse the relocation table, I will not repeat it here.
Considerations for ShellCode authoring
When writing ShellCode code, be sure to follow the following principles to avoid some trouble, or unexpected errors will occur:
In addition to eax / rax other registers, be sure to save, because other function calls have a variety of calling conventions, be sure not to affect them, otherwise there will be errors. Why should eax / rax be treated differently? because generally speaking, it is only used as a return value, and the result returned by calling the function must modify it, so it is not necessary.
When using ASMJIT to generate assembly, when using instructions similar to MOV, be sure to note that if you want to write how much data must be reflected in the target Operand, for example, if you want to move the size of WORD, do not use eax with ax, otherwise it will generate assembly instructions without error, the result is not the same as the code you want to generate.
Be sure to pay attention to stack balance, which is very important, especially in 64-bit and 32-bit operating systems.
At this point, the study on "how to use C++ to achieve XOR encryption" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.