2011-08-03 6 views
13

컴파일 할 때 문자열을 암호화/인코딩하여 원래 문자열이 컴파일 된 실행 파일에 나타나지 않도록하고 싶습니다.컴파일시 문자열 리터럴 암호화/난독 처리

몇 가지 예를 보았지만 문자열 리터럴을 인수로 사용할 수 없습니다. 다음 예를 참조하십시오.

template<char c> struct add_three { 
    enum { value = c+3 }; 
}; 

template <char... Chars> struct EncryptCharsA { 
    static const char value[sizeof...(Chars) + 1]; 
}; 

template<char... Chars> 
char const EncryptCharsA<Chars...>::value[sizeof...(Chars) + 1] = { 
    add_three<Chars>::value... 
}; 

int main() { 
    std::cout << EncryptCharsA<'A','B','C'>::value << std::endl; 
    // prints "DEF" 
} 

나는 각 문자를 별도로 제공하고 싶지 않습니다.

EncryptString<"String to encrypt">::value 

또한 이와 같은 몇 가지 예있다 :

#define CRYPT8(str) { CRYPT8_(str "\0\0\0\0\0\0\0\0") } 
#define CRYPT8_(str) (str)[0] + 1, (str)[1] + 2, (str)[2] + 3, (str)[3] + 4, (str)[4] + 5, (str)[5] + 6, (str)[6] + 7, (str)[7] + 8, '\0' 

// calling it 
const char str[] = CRYPT8("ntdll"); 

을하지만 문자열의 크기를 제한 내 목표는 리터럴 문자열을 전달하고자하는 것입니다 다음과 같습니다.

내가 원하는 것을 얻을 수있는 방법이 있습니까?

+8

이 유형의 문제에 대한 일반적인 접근 방법은 원본 파일을 입력으로 사용하고 출력으로 수정 된 파일을 작성하는 스크립트를 작성하는 것입니다. 그러면이 파일이 빌드 프로세스에서 사용됩니다. 이 경우, 스크립트는'EncryptString < "String을 찾아">'를 암호화하고 암호화/암호화 된 버전으로 문자열을 대체합니다. – jdigital

답변

1

나는이 질문에 업데이트 된 대답이 필요하다고 생각합니다.

몇 년 전에이 질문을했을 때, 나는 the difference between obfuscation and encryption을 고려하지 않았습니다. 이 차이를 알았 더라면, 전에 제목에 난독 화이라는 용어를 포함 시켰을 것입니다. 효과적이고 합리적으로 간단한 방법으로 (나는 아직 시도하지 않은 있지만, 아마도 암호화)

C++ 11과 C++ 14

이 가능 컴파일 시간 문자열 난독 화를 구현 할 수 있도록 기능을 가지고 있습니다 이미 완료되었습니다.

ADVobfuscator은 Sebastien Andrivet이 C++ 11/14를 사용하여 외부 도구 (C++ 코드)를 사용하지 않고 컴파일 시간 난독 화 코드를 생성하는 데 사용하는 난독 화 라이브러리입니다. 추가 빌드 단계를 만들 필요가 없습니다. 단지 포함하고 사용하십시오. 외부 도구 나 빌드 단계를 사용하지 않는 더 나은 컴파일 타임 문자열 암호화/난독 처리 구현을 모르겠습니다. 그렇게한다면 공유하십시오.

문자열을 흐트러 뜨릴뿐만 아니라 함수 호출을 임의로 난독화할 수있는 컴파일 타임 FSM (Finite State Machine) 및 컴파일 타임 의사 난수 생성기와 같은 다른 유용한 기능이 있지만 범위를 벗어납니다 이 대답.

#include "MetaString.h" 

using namespace std; 
using namespace andrivet::ADVobfuscator; 

void Example() 
{ 
    /* Example 1 */ 

    // here, the string is compiled in an obfuscated form, and 
    // it's only deobfuscated at runtime, at the very moment of its use 
    cout << OBFUSCATED("Now you see me") << endl; 

    /* Example 2 */ 

    // here, we store the obfuscated string into an object to 
    // deobfuscate whenever we need to 
    auto narrator = DEF_OBFUSCATED("Tyler Durden"); 

    // note: although the function is named `decrypt()`, it's still deobfuscation 
    cout << narrator.decrypt() << endl; 
} 

당신은 당신의 자신의 매크로 매크로 DEF_OBFUSCATEDOBFUSCATED을 대체 할 수

여기 ADVobfuscator를 사용하여 간단한 문자열 난독 예입니다. 예 :

#define _OBF(s) OBFUSCATED(s) 

... 

cout << _OBF("klapaucius"); 

어떻게 작동합니까? 당신이 MetaString.h이 두 매크로의 정의를 살펴 경우

, 당신은 볼 수 있습니다 :

#define DEF_OBFUSCATED(str) MetaString<andrivet::ADVobfuscator::MetaRandom<__COUNTER__, 3>::value, andrivet::ADVobfuscator::MetaRandomChar<__COUNTER__>::value, Make_Indexes<sizeof(str) - 1>::type>(str) 

#define OBFUSCATED(str) (DEF_OBFUSCATED(str).decrypt()) 

을 기본적으로 MetaString 클래스 (문자열 난독의 핵심)의 세 가지 변종이있다 . 각각은 자체 난독 화 알고리즘을 가지고 있습니다. 라이브러리의 의사 난수 생성기 (MetaRandom)와 임의의 char을 사용하여 컴파일 타임에 임의로 선택됩니다.이 알고리즘은 선택한 알고리즘에서 문자열 문자 xor에 사용됩니다.

"이봐, 그러나 우리는 수학, 3 알고리즘 * 255 가능한 문자 키 (0이 사용되지 않음) = 모호한 문자열의 765 개 변종 할 경우"

당신이 옳은 것입니다. 같은 문자열은 765 가지 방법으로 만 난독 화 될 수 있습니다. 좀 더 안전한 것을 필요로하는 이유가 있다면 (당신은 편집증 적이거나 응용 프로그램에 보안 강화가 요구됩니다) 더 강력한 난독 화 또는 암호화를 사용하여 라이브러리를 확장하고 자신의 알고리즘을 구현할 수 있습니다 (White-Box cryptography은 lib의 로드맵에 있음).


여기서 어떻게 난독 화 된 문자열을 저장합니까?

이 구현에 대해 흥미로운 점 중 하나는 실행 파일의 데이터 섹션에 난독 화 문자열을 저장하지 않는다는 것입니다. 대신 스택에있는 MetaString 개체 자체에 정적으로 저장되며 알고리즘은 런타임에 해당 알고리즘을 디코딩합니다. 이 방법을 사용하면 정적으로 또는 런타임에 난독 화 문자열을 찾기가 훨씬 더 어려워집니다.

직접 구현에 대해 자세히 살펴볼 수 있습니다. 이는 매우 훌륭한 기본 난독 화 솔루션이며보다 복잡한 난독 화 솔루션의 출발점이 될 수 있습니다.

+0

링크 된 도구를 사용하는 방법에 대한 답변이 자세하게 설명되어 있지만 여기에 구현의 세부 사항을 추가 할 수 있다면 좋을 것입니다. 그렇지 않으면 링크가 죽은 경우 향후 독자는 액세스 권한이없는 까다로운 개발자의 구현 방법 만 볼 수있게되며 이는 다소 격분하게됩니다. –

+0

제안 해 주셔서 감사합니다. 구현 세부 정보를 게시합니다. – karliwson

3

ISO C++ 표준에 의해 허용되지 않았기 때문에 찾은 예제가 템플릿 인수로 문자열 리터럴을 취할 수없는 이유는 그 이유입니다. 왜냐하면 C++에는 문자열 클래스가 있지만 문자열 리터럴은 여전히 ​​const char *이기 때문입니다. 따라서 컴파일 타임 문자열 리터럴의 문자에 액세스 할 수 있더라도이를 수정하거나 (정의되지 않은 동작으로 이어질 수 없음) 변경할 수 없습니다.

내가 볼 수있는 유일한 방법은 컴파일러 전에 전 처리기에서 처리하므로 정의를 사용하는 것입니다. 어쩌면 부스트가 도움이 될 것입니다.

2

매크로 기반 솔루션은 가변 인수를 사용하여 문자열의 각 부분을 단일 토큰으로 전달하는 것입니다. 그런 다음 토큰을 문자열로 변환하고 암호화하여 모든 토큰을 연결하십시오. 최종 결과는 다음과 같습니다.

CRYPT(m y _ s t r i n g) 

여기서 _는 공백 문자 리터럴에 대한 일부 자리 표시 자입니다. 끔찍하게 지저분하고 나는이 모든 다른 솔루션을 선호합니다.

Boost.PP 시퀀스가 ​​더 이상 좋아 보이지는 않지만이 기능을 사용할 수 있습니다. 자신을 저장

#include <iostream> 
#include <boost/preprocessor/stringize.hpp> 
#include <boost/preprocessor/seq/for_each.hpp> 

#define GARBLE(x) GARBLE_ ## x 
#define GARBLE_a x 
#define GARBLE_b y 
#define GARBLE_c z 

#define SEQ (a)(b)(c) 
#define MACRO(r, data, elem) BOOST_PP_STRINGIZE(GARBLE(elem)) 

int main() { 
    const char* foo = BOOST_PP_SEQ_FOR_EACH(MACRO, _, SEQ); 
    std::cout << foo << std::endl; 
} 
7

문자열을 암호화 한 후 컴파일 된 cpp를 소스 파일을 생성하는 독립 실행 형 프로그램 템플릿 메타 프로그래밍에 그냥 쓰기 선 아래로 문제의 힙.이 프로그램은 컴파일하기 전에 실행 한 것이다 사용할 암호화 된 문자열을 포함하는 cpp 및/또는 헤더 파일을 생성합니다. (비어있는)

  1. encrypted_string.cpp 및 encrypted_string.h
  2. 이상 입력으로 텍스트 파일을 소요 스크립트 또는 독립 실행 형 응용 프로그램 encrypted_string 글을 참고하세요 : 그래서 여기

    은 당신이 무엇을 시작이다 .cpp 및 encrypted_string.h

코드에 존재하지 않는 변수에 대한 참조가 있기 때문에 컴파일에 실패합니다. 당신은 더 똑똑해 질 수는 있지만, 시작하면 충분합니다.