我的编程空间,编程开发者的网络收藏夹
学习永远不晚

使用c++实现异或加密的代码示例

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

使用c++实现异或加密的代码示例

加密原理

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

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

已知两个数AB,如果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 编写注意事项

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

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

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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

使用c++实现异或加密的代码示例

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

怎么使用c++实现异或加密

这篇文章主要介绍“怎么使用c++实现异或加密”,在日常操作中,相信很多人在怎么使用c++实现异或加密问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么使用c++实现异或加密”的疑惑有所帮助!接下来,请跟着小编
2023-06-30

C#利用异或算法实现加密解密

这篇文章主要为大家详细介绍了C#如何利用异或算法实现加密解密的功能,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以跟随小编一起了解一下
2023-01-03

python实现希尔密码加密的示例代码

目录原理实现原理 希尔密码是运用基本矩阵论原理的替换密码,由Lester S. Hill在1929年发明。 每个字母当作26进制数字:A=0, B=1, C=2… 一串字母当成n维向量,跟一个n×n的矩阵相乘,再将得出的结果模26。(注意用
2022-06-02

C#实现对文件进行加密保护的示例代码

这篇文章主要为大家详细介绍了如何利用C#实现对文件进行加密保护的功能,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以跟随小编一起了解一下
2022-12-31

怎么使用PHP实现C语言中的异或加密算法

本篇内容介绍了“怎么使用PHP实现C语言中的异或加密算法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、异或加密算法简介异或加密算法是一种
2023-07-05

Go语言实现Sm2加解密的示例代码

本文主要介绍了Go语言实现Sm2加解密的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-03-19

Oracle实现透明数据加密的代码示例

目录前言实现 TDE 的步骤1. 创建主密钥2. 创建证书3. 创建数据库加密密钥(DEK)4. 启用数据库加密5. 验证加密状态示例脚本总结其他数据库的 TDE 实现oracle 数据库mysql 数据库前言透明数据加密(TDE)是一种
Oracle实现透明数据加密的代码示例
2024-09-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录