2010-06-16

Шифрование строк

Иногда необходимо зашифровать строки в программе, это хоть немного, но затрудняет реверсинг. Недавно и мне потребовалось решить эту задачу. Решено было написать некоторый аналог препроцессора на python-е. Препроцессор просто заменяет макрос _C на вызов функции CSDecrypt. Например, этот код:

#include <stdio.h>
#include <windows.h>
#include "_CSD.h"

int f(char * t) {
  printf(_C("|t:%s| "),t);
  return 0;
}

int main(int argc, char ** argv) {
  f(_C("testing"));
  f(_C("test2"));
  return 1;
}


будет преобразован в следующий:

#include <stdio.h>
#include <windows.h>
#include "_CSD.h"

int f(char * t) {
  printf(CSDecrypt("\x00\xf2\xfb\xaa\xb4\xe1\xef\xb4",7,142),t);
  return 0;
}

int main(int argc, char ** argv) {
  f(CSDecrypt("\x00\xe7\xf1\xe6\xe2\xfe\xf6\xfe",7,147));
  f(CSDecrypt("\x00\x14\x04\x11\x17\x56",5,96));
  return 1;
}


_CSD.h содержит функцию расшифровки.

#pragma once

inline char* CSDecrypt(char *str, size_t len, BYTE key) {
  char *flag = str;
  str++;
  if (*flag=='\x01') {
    return str;
  }
  for (int i=0;i<len;i++) {
    str[i]^=(key+i);
  }
  *flag = '\x01';
  return str;
}



Желательно передать компилятору /Ob1, т.к. inline. И ещё, важный момент, память, в которай расположенна строка, должна быть доступна для записи, иначе будет исключение C0000005 (ACCESS VIOLATION).

вот сам код "препроцессора":

import sys, re
from random import randint

def XorStr(str,key):
  retval = ""
  for i in range(0,len(str)):
    t = ord(str[i])^int(key+i)
    retval += chr(t)
  return retval

def FmtXorStr(str):
  retval = r"\x00"
  for x in str:
    retval += r"\x%02x" % ord(x)
  return retval

def _C(obj):
  key = randint(1,254)
  str = XorStr(obj.group(1),key)
  retval = 'CSDecrypt("%s",%d,%d)' % (FmtXorStr(str),len(obj.group(1)),key)
  return retval

def main():
  try:
    f = open(sys.argv[1],"r")
    code = f.read()
    f.close()
    dest = open(sys.argv[2],"w")
  except:
    print "%s <in> <out>" % sys.argv[0]
    return 0
  
  r = re.sub(r'_C\("(.*?)"\)',_C,code)
  dest.write(r)
  dest.close()
  return 1

main()



Я сейчас почти полностью перешел на vim + scons. Вот пример как подключить "препроцессор" (pre.py) к scons:

env = Environment(
  CCFLAGS = "/Ob1 /c /D_CSD",
  LINKFLAGS = "/MERGE:.rdata=.text /MERGE:.data=.text /SECTION:.text,EWR"
)

PyPre = Builder(action = 'pre.py $SOURCE $TARGET',
    src_suffix = '.cpp', suffix = '.cxx')

env["BUILDERS"]["PyPre"] = PyPre

for x in Glob("*.cpp"):
  env.PyPre(x)

env.Program("test.exe",Glob("*.cxx"))


Конечно могут быть всякие баги-глюки, т.к. не особо тестилось всё это. Но осоновная идея я думаю понятна. Из известных недостатков:

1. Нельзя юзать так: char a[] = _C("test");
2. Не корректно обрабатываются спецсимволы ( например \n\r )
3. ...

UPD
проблема со спецсимволами решается через .decode("string_escape")

Комментариев нет:

Архив