【问题标题】:Obfuscate std::array using constexpr使用 constexpr 混淆 std::array
【发布时间】:2018-03-16 10:05:09
【问题描述】:

我正在寻找一个能够通过增加值来转换std::array 的小函数。该函数必须是编译时函数。

我能够编写一个小的 constexpr 函数,它对长度为 3 的数组执行此操作,但我无法将其推广到任意长度的 std::arrays。我也未能将其概括为包含与chars 不同的内容。

有人知道怎么做吗?

#include <array>
#include <iostream>
#include <valarray>

constexpr std::array<char,3> obfuscate(const std::array<char,3>& x)  {
     return std::array<char, 3>{x.at(0)+1, x.at(1) + 2, x.at(2) + 3 };
}

/* Won't compile

template<typename T,typename S, template<typename, typename> L=std::array<T, U>>
constexpr L<T,U> obfuscate(const L<T, U>& x) {
    return {x.at(0) + 1, x.at(0) + 2, x.at(0) + 3 };
}
*/

std::ostream& operator<<(std::ostream& str, const std::array<char, 3>& x) {
    for (auto i = 0; i < 3; i++) {
        str << x.at(i);
    }
    return str;
}

int main(int argc, char** args) {
    std::array<char, 3> x{ 'a','b','c' };
    std::cout << x << std::endl;
    std::cout << obfuscate(x) << std::endl;
//  std::cout << obfuscate<3>(x) << std::endl;
}

【问题讨论】:

  • 您是否希望真正混淆数组或让您的程序正常工作?我有一堆用于前者的代码,尽管它通常会杀死大型包的 MSVC 编译器。
  • @Mikhail:我真的很想混淆我的字符串,这样就没有人可以读取编译文件中的字符串。我的琴弦通常很短。我只是好奇如何做到这一点。
  • @Holt:我必须坚持使用 C++11。但是你的解决方案是什么?是编译时表达式吗?
  • 目的是什么?混淆不是加密,攻击者要对你的字符串进行混淆并不难,那么为什么还要麻烦呢?
  • 我正在为好奇什么可以在编译时完成而烦恼。很明显,只要付出足够的努力就可以破解混淆器。

标签: c++ variadic-templates template-meta-programming constexpr stdarray


【解决方案1】:

你可以使用std::index_sequence:

template<class T, std::size_t N, std::size_t... Is>
constexpr std::array<T, N> helper (const std::array<T, N> &x, std::index_sequence<Is...>) {
     return std::array<T, N>{static_cast<T>(x.at(Is)+Is+1)...};
}

template<class T, std::size_t N>
constexpr std::array<T, N> obfuscate(const std::array<T, N> &x) {
     return helper(x, std::make_index_sequence<N>{});
}

【讨论】:

  • 干得好。似乎是正确的做法。不幸的是,它似乎没有混淆字符串?知道为什么吗?我调整了我的 operator
  • @Aleph0 您在自己的代码中为每个项目使用x.at(0)。我只是复制它。是不是笔误?
  • 对不起,这是一个类型。我想在我的数组中添加越来越多的数字。刚刚纠正了我的错误。
  • 像魅力一样工作。我真的需要一些时间来消化你的解决方案。看来,我可以从中学到很多东西。
  • 我想知道是否可以以混淆(“字符串”)的方式使用它。但是我需要一种方法来将 const char* 转换为 std::array&lt;char,N&gt;?
【解决方案2】:

有一些使用元组包的方法,除了 MSVC 在编译大字符串时存在性能问题之外,这些方法都很棒。

我发现这种折衷方案在 MSVC 中效果很好。

template<typename I>
struct encrypted_string;

template<size_t... I>
struct encrypted_string<std::index_sequence<I...>>
{
    std::array<char, sizeof...(I)+1> buf;

    constexpr static char encrypt(char c) { return c ^ 0x41; }
    constexpr static char decrypt(char c) { return encrypt(c); }
    constexpr explicit __forceinline encrypted_string(const char* str)
        : buf{ encrypt(str[I])... } { }
    inline const char* decrypt()
    {
        for (size_t i = 0; i < sizeof...(I); ++i)
        {
            buf[i] = decrypt(buf[i]);
        }
        buf[sizeof...(I)] = 0;
        return buf.data();
    }
};
#define enc(str) encrypted_string<std::make_index_sequence<sizeof(str)>>(str)

然后在某个地方

auto stringo = enc(R"(  
    kernel void prg_PassThru_src(const global unsigned short * restrict A, int srcstepA, int srcoffsetA,
    global float * restrict Beta, int srcstepBeta, int srcoffsetBeta,
    int rows, int cols) {
        int x = get_global_id(0);
        int y0 = get_global_id(1);
        if (x < cols) {
            int srcA_index = mad24(y0, srcstepA / 2, x + srcoffsetA / 2);
            int srcBeta_index = mad24(y0, srcstepBeta / 4, x + srcoffsetBeta / 4);
            Beta[srcBeta_index] = A[srcA_index];
        }
    }
//somewhere later
cv::ocl::ProgramSource programSource(stringo.decrypt());

您可以查看此人的谈话以了解更复杂的方法: https://www.blackhat.com/docs/eu-14/materials/eu-14-Andrivet-C-plus-plus11-Metaprogramming-Applied-To-software-Obfuscation.pdf

【讨论】:

    猜你喜欢
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    • 1970-01-01
    • 2020-03-22
    • 2019-01-31
    • 2013-01-27
    相关资源
    最近更新 更多