经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
使用c++实现异或加密的代码示例
来源:jb51  时间:2022/4/11 20:16:14  对本文有异议

加密原理

由于展示最基本最简单的实现,使用算法加密就没用复杂的。如果使用比较复杂的加密,首先你在C++代码层面和汇编层面要有配套的代码,C++负责加密,汇编负责自我解密,否则你加密完了,结果加密后的PE文件自己又解密不了,这就很尴尬。

在所有加密算法,异或加密是最简单的,也是最好是实现的。我们来介绍异或加密的原理。

已知两个数AB,如果A xor B = C,则C xor B = A,其中xor表示异或运算符。如果不理解,这个是入门编程的最基本的知识,请自行补缺,这里我就不唠叨了。

异或加密的实现

下面是我们实现异或加密的相关函数:

  1. // GNU AFFERO GENERAL PUBLIC LICENSE
  2. //Version 3, 19 November 2007
  3. //Copyright(C) 2007 Free Software Foundation, Inc.
  4. //Everyone is permitted to copyand distribute verbatim copies
  5. //of this license document, but changing it is not allowed.
  6. // Author : WingSummer (寂静的羽夏)
  7. //Warning: You can not use it for any commerical use,except you get
  8. // my AUTHORIZED FORM ME!This project is used for tutorial to teach
  9. // the beginners what is the PE structure and how the packer of the PE files works.
  10. BOOL CWingProtect::XORCodeSection(BOOL NeedReloc, BOOL FakeCode)
  11. {
  12. using namespace asmjit;
  13. if (_lasterror != ParserError::Success) return FALSE;
  14. auto filesize = peinfo.FileSize.QuadPart;
  15. CodeHolder holder;
  16. /// <summary>
  17. /// PointerToRawData
  18. /// </summary> auto p = peinfo.PCodeSection->PointerToRawData;
  19. /// <summary>
  20. /// SizeOfRawData
  21. /// </summary>
  22. auto sizecode = peinfo.PCodeSection->SizeOfRawData;
  23. auto repeat = sizecode;
  24. BYTE* shellcode;
  25. INT3264 ccount;
  26. if (is64bit)
  27. {
  28. Environment env(Arch::kX64);
  29. holder.init(env);
  30. x86::Assembler a(&holder);
  31. Label loop = a.newLabel();
  32. x86::Mem mem;
  33. mem.setSegment(x86::gs);
  34. mem.setOffset(0x60);
  35. //生成加密 shellcode,此处的 rax = ImageBase
  36. a.push(x86::rcx);
  37. a.push(x86::rdi);
  38. //xor 解密
  39. a.mov(x86::rax, mem);
  40. a.mov(x86::rax, x86::qword_ptr(x86::rax, 0x10));
  41. a.mov(x86::rdi, x86::rax);
  42. a.add(x86::rdi, peinfo.PCodeSection->VirtualAddress);
  43. a.mov(x86::rcx, repeat);
  44. a.bind(loop);
  45. if (FakeCode) FakeProtect(a);
  46. a.xor_(x86::byte_ptr(x86::rdi), 0x55);
  47. a.inc(x86::rdi);
  48. a.dec(x86::rcx);
  49. a.test(x86::rcx, x86::rcx);
  50. a.jnz(loop);
  51. //确保此时 rax 或 eax 存放的是 ImageBase ,否则是未定义行为
  52. if (NeedReloc)
  53. RelocationSection(a);
  54. a.pop(x86::rdi);
  55. a.pop(x86::rcx);
  56. a.ret();
  57. shellcode = a.bufferData();
  58. ccount = holder.codeSize();
  59. }
  60. else
  61. {
  62. Environment env(Arch::kX86);
  63. holder.init(env);
  64. x86::Assembler a(&holder);
  65. Label loop = a.newLabel();
  66. x86::Mem mem;
  67. mem.setSegment(x86::fs);
  68. mem.setOffset(0x30);
  69. //生成加密 shellcode
  70. a.push(x86::ecx);
  71. a.push(x86::edi);
  72. a.mov(x86::eax, mem);
  73. a.mov(x86::eax, x86::dword_ptr(x86::eax, 0x8));
  74. a.mov(x86::edi, x86::eax);
  75. a.add(x86::edi, peinfo.PCodeSection->VirtualAddress);
  76. a.mov(x86::ecx, repeat);
  77. a.bind(loop);
  78. if (FakeCode) FakeProtect(a);
  79. a.xor_(x86::byte_ptr(x86::edi), 0x55);
  80. a.inc(x86::edi);
  81. a.dec(x86::ecx);
  82. a.test(x86::ecx, x86::ecx);
  83. a.jnz(loop);
  84. //确保此时 rax 或 eax 存放的是 ImageBase ,否则是未定义行为
  85. if (NeedReloc)
  86. RelocationSection(a);
  87. a.pop(x86::edi);
  88. a.pop(x86::ecx);
  89. a.ret();
  90. shellcode = a.bufferData();
  91. ccount = holder.codeSize();
  92. }
  93. //异或加密
  94. auto se = (BYTE*)b;
  95. for (UINT i = 0; i < repeat; i++)
  96. {
  97. se[i] ^= (BYTE)0x55;
  98. }
  99. //加密完毕,写 Shellcode
  100. encryptInfo.XORDecodeShellCode = (UINT)peinfo.PointerOfWingSeciton;
  101. auto ws = GetPointerByOffset(peinfo.WingSecitonBuffer, peinfo.PointerOfWingSeciton);
  102. memcpy_s(ws, ccount, shellcode, ccount);
  103. peinfo.PointerOfWingSeciton += ccount;
  104. if (!NeedReloc)
  105. {
  106. auto tmp = (PIMAGE_SECTION_HEADER)TranModPEWapper(peinfo.PCodeSection);
  107. tmp->Characteristics |= IMAGE_SCN_MEM_WRITE;
  108. }
  109. return TRUE;
  110. }

在C++代码层面,加密代码区内容相关的代码如下:

  1. //异或加密
  2. auto se = (BYTE*)b;
  3. for (UINT i = 0; i < repeat; i++)
  4. {
  5. se[i] ^= (BYTE)0x55;
  6. }

^表示异或运算符,在汇编层面,以64位为例,实现如下所示:

  1. a.mov(x86::rax, mem);
  2. a.mov(x86::rax, x86::qword_ptr(x86::rax, 0x10));
  3. a.mov(x86::rdi, x86::rax);
  4. a.add(x86::rdi, peinfo.PCodeSection->VirtualAddress);
  5. a.mov(x86::rcx, repeat);
  6. a.bind(loop);
  7. if (FakeCode) FakeProtect(a);
  8. a.xor_(x86::byte_ptr(x86::rdi), 0x55);
  9. a.inc(x86::rdi);
  10. a.dec(x86::rcx);
  11. a.test(x86::rcx, x86::rcx);
  12. a.jnz(loop);

可以看出来汇编写起来比写C++代码麻烦多了,里面有一些代码可能有一些其他的考虑,我们这里说一下:

首先是FakeProtect,这个就是生成花指令,这里不多说,后面在介绍。还有一个函数比较注意RelocationSection,这个函数是用来生成做重定位的汇编代码的,为什么要有这个函数呢?

比如我只有异或加密,我们是在硬编码的层面进行的加密,PE被加载进入的时候如果基址不和预想的那样,就会查是否有重定位表,如果有的话就解析并修复。但是,我们的代码是加密的,而重定位表没做修改,它就会错误的把被加密的硬编码进行重定位,这个是不能够允许的。所以我们需要摧毁重定位表,可以看到CWingProtect::Proctect里面有一个函数DestoryRelocation,这个作用就是用来销毁它的,不让PE加载器帮我们做重定位。

综上所述,我们需要自己做重定位,我们需要在汇编层面来实现重定位表的修复,我们来看一下相关代码:

  1. //
  2. // GNU AFFERO GENERAL PUBLIC LICENSE
  3. //Version 3, 19 November 2007
  4. //
  5. //Copyright(C) 2007 Free Software Foundation, Inc.
  6. //Everyone is permitted to copyand distribute verbatim copies
  7. //of this license document, but changing it is not allowed.
  8. // Author : WingSummer (寂静的羽夏)
  9. //
  10. //Warning: You can not use it for any commerical use,except you get
  11. // my AUTHORIZED FORM ME!This project is used for tutorial to teach
  12. // the beginners what is the PE structure and how the packer of the PE files works.
  13.  
  14. void CWingProtect::RelocationSection(asmjit::x86::Assembler& a)
  15. {
  16. using namespace asmjit;
  17.  
  18. Label loop_xor = a.newLabel();
  19. Label loop_reloc = a.newLabel();
  20. Label loop_rt = a.newLabel();
  21. Label endproc = a.newLabel();
  22. auto rdd = peinfo.PDataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
  23. if (is64bit)
  24. {
  25. a.nop();
  26. a.push(x86::rdi);
  27. a.push(x86::rcx);
  28. a.push(x86::rsi); //征用 rsi
  29. a.mov(x86::rsi, rdd.VirtualAddress); //重定位表基址
  30. a.add(x86::rsi, x86::rax);
  31. a.push(x86::rdx); //征用 rdx
  32. a.push(x86::r10);
  33. a.mov(x86::r10, peinfo.ImageBase); //PE 加载后,该值会被重定位,只能写死
  34. a.sub(x86::r10, x86::rax);
  35. a.jz(endproc);
  36.  
  37. a.bind(loop_rt);
  38. a.mov(x86::edi, x86::dword_ptr(x86::rsi)); //偏移基址地址
  39. a.add(x86::rdi, x86::rax); //此时 rdi 为加载到内存的虚拟基址地址
  40. //计数
  41. a.mov(x86::ecx, x86::dword_ptr(x86::rsi, 4));
  42. a.sub(x86::ecx, 8);
  43. a.shr(x86::ecx, 1); //此时为重定位表的真实项目个数
  44. a.add(x86::rsi, 8); //将指针指向该索引下的第一个重定位项目
  45. a.bind(loop_reloc);
  46. a.dec(x86::rcx);
  47. a.mov(x86::dx, x86::word_ptr(x86::rsi, x86::rcx, 1));
  48. a.test(x86::dx, 0xF000);
  49. a.jz(loop_reloc); //contine;
  50. a.and_(x86::edx, 0xFFF);
  51. a.add(x86::rdx, x86::rdi);
  52. a.sub(x86::qword_ptr(x86::rdx), x86::r10); //修正
  53. a.cmp(x86::rcx, 0);
  54. a.ja(loop_reloc);
  55. a.sub(x86::rsi, 8); //重新指向表头
  56. a.mov(x86::edx, x86::dword_ptr(x86::rsi, 4));
  57. a.add(x86::rsi, x86::rdx); //指向下一个
  58. a.mov(x86::edx, x86::dword_ptr(x86::rsi));
  59. a.test(x86::edx, x86::edx);
  60. a.jnz(loop_rt);
  61. a.bind(endproc);
  62. a.pop(x86::r10);
  63. a.pop(x86::rdx);
  64. a.pop(x86::rsi); //释放 rsi 自由身
  65. a.pop(x86::rcx);
  66. a.pop(x86::rdi);
  67. }
  68. else
  69. {
  70. a.push(x86::edi);
  71. a.push(x86::ecx);
  72. a.push(x86::esi); //征用 rsi
  73. a.mov(x86::esi, rdd.VirtualAddress); //重定位表基址
  74. a.add(x86::esi, x86::eax);
  75. a.push(x86::edx); //征用 edx
  76. a.push((DWORD32)peinfo.ImageBase); //x86寄存器没那么多,只能自己维护一个局部变量
  77. a.sub(x86::dword_ptr(x86::esp), x86::rax);
  78. a.jz(endproc);
  79.  
  80. a.bind(loop_rt);
  81. a.mov(x86::edi, x86::dword_ptr(x86::esi)); //偏移基址地址
  82. a.add(x86::edi, x86::eax); //此时 rdi 为加载到内存的虚拟基址地址
  83. //计数
  84. a.mov(x86::ecx, x86::dword_ptr(x86::esi, 4));
  85. a.sub(x86::ecx, 8);
  86. a.shr(x86::ecx, 1); //此时为重定位表的真实项目个数
  87. a.add(x86::esi, 8); //将指针指向该索引下的第一个重定位项目
  88. a.bind(loop_reloc);
  89. a.dec(x86::ecx);
  90. a.mov(x86::dx, x86::word_ptr(x86::rsi, x86::ecx, 1));
  91. a.test(x86::dx, 0xF000);
  92. a.jz(loop_reloc); //contine;
  93. a.and_(x86::edx, 0xFFF);
  94. a.add(x86::edx, x86::edi);
  95. a.push(x86::eax); //使用局部变量
  96. a.mov(x86::eax, x86::dword_ptr(x86::esp, 4)); //注意被 push 了一个,所以加个偏移
  97. a.sub(x86::dword_ptr(x86::edx), x86::eax); //修正
  98. a.pop(x86::eax);
  99. a.cmp(x86::ecx, 0);
  100. a.ja(loop_reloc);
  101. a.sub(x86::esi, 8); //重新指向表头
  102. a.mov(x86::edx, x86::dword_ptr(x86::esi, 4));
  103. a.add(x86::esi, x86::rdx); //指向下一个
  104. a.mov(x86::edx, x86::dword_ptr(x86::esi));
  105. a.test(x86::edx, x86::edx);
  106. a.jnz(loop_rt);
  107. a.bind(endproc);
  108. a.add(x86::esp, 4); //释放局部变量
  109. a.pop(x86::edx);
  110. a.pop(x86::esi); //释放 rsi 自由身
  111. a.pop(x86::ecx);
  112. a.pop(x86::edi);
  113. }
  114. //将所有的节全部改为可写
  115. auto length = peinfo.NumberOfSections;
  116. for (UINT i = 0; i < length; i++)
  117. {
  118. ((PIMAGE_SECTION_HEADER)TranModPEWapper(&peinfo.PSectionHeaders[i]))
  119. ->Characteristics |= IMAGE_SCN_MEM_WRITE;
  120. }
  121. }

对于以上代码你可能有一些疑问,我这里说一下:
为什么调用a.nop()来生成没有用的指令,这个是我用来方便调试我生成的ShellCode用的,否则会生成一大坨汇编到后来自己也不清楚自己在调试啥的,通过这个nop我就可以清楚的直到我到那里了,如果出错的话我也方便进行定位。
此函数最后生成完ShellCode之后又将所有的节全部改为可写属性,这是为什么呢?因为线性内存是有属性的,如果我没有将其设置可写,如果它是只读内存,如果我对它做重定位修改的话,就会报内存访问错误,导致程序崩溃。
怎么用汇编来解析重定位表,这里就不赘述了。

ShellCode 编写注意事项

在编写ShellCode代码的时候,请一定保证如下原则,避免一些麻烦,否则会出现出乎意料的错误:

  • 除了 eax / rax 其他寄存器用到的话,一定要注意保存好,因为其它函数调用有各种调用约定,一定不要影响它们,否则会出错。为什么要对 eax / rax 区别对待,因为通常来说它只用做返回值,调用函数返回结果一定会修改它,所以大可不必。
  • 在使用 ASMJIT 生成汇编的时候,使用类似 MOV 的指令的时候,一定要注意如果要写入多大的数据一定要在目标操作数体现数来,比如要移动 WORD 大小的话,用 ax 就不要用 eax,否则它正常生成汇编指令不报错,结果和你想生成的代码不一样。
  • 一定要注意堆栈平衡,这个是非常重要的东西,在64位尤甚,32位的操作系统也是十分注意堆栈平衡的。

以上就是使用c++实现异或加密的代码示例的详细内容,更多关于c++异或加密示例的资料请关注w3xue其它相关文章!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号