C#代码分析器(C#游戏代码注入)

来源:互联网 发布:php is numeric 漏洞 编辑:程序博客网 时间:2024/06/01 17:02

简介

  在进行C#代码注入的过程中,写的比较复杂的逻辑,但是reflector注入只能一个个函数来进行,而且添加paramter非常复杂,这里做了一个简单的代码分析器,帮助所有代码集中到一个函数中。

      虽然感觉上比较简单,但做的过程中,花费了大半天的时间,这里把遇到的问题总结一下,给大家后续开发一些启示。

  理论上C语言格式的都可以用这个解析把多个函数包含在一个函数里面


Reflector注入过程

  • 1 导入相应的dll
  • 2 tools decompile。 点右键 replaceWithCode。
  • 3 子类添加函数基类,然后写函数。
  • 4 在dll上右键Reflexil -> SaveAs相关dll即可。

 

遇到的问题

  因为relector一次只支持注入一个函数,而我们写的显示代码是有多个函数的。

      即使新加入一个类,也需要在这个类里面单独加入各个函数。

     同时代码里面有互相的嵌套,而且有返回值和各个参数,如果单个的加非常的麻烦,而且reflector不支持返回值,相关的值只能放入输出参数,和原有的代码就大大违背了。

所以这里写了一个简单的代码分析器,用这个解析把多个函数包含在一个函数里面。


代码格式

首先读入的代码要编译通过

需要一些简单的约束:

  • 1子函数必须有返回值,且返回值不能用和次子函数的参数相同。只有一个返回的出口。上支持上任意返回类型,只是父函数必须调用一下子函数返回的值。
  • 2 调用函数的参数中不支持嵌套调用自己写的函数。
  • 3 除非是返回值,否则临时变量需要自行设的是unique的。否则会重复定义。
  • 4 “{}”这种单独占一行,一般C#编辑器会自动解析成这样。
  • 5 函数不能循环调用,解析会进入循环。
  • 6 目前只支持+=和+,如果需要其他运算符,在tpl_func_split中加。  特殊的运算序列没有做支持,当时这个分析器只是为了输出日志方便用的。

 

输入格式

  //(joint为已知的Joint数据结构)        public string A(string p)        {            string tmpA = "add a" + p;            return tmpA;        }        public string B(Jointjoint, string c)        {            string tmp = "add b\n";            tmp += A(joint.format) + joint;            return tmp;        }        public void Jump()        {            string tmp = "start ===\n";            //tmp += "A " + A("12");            //tmp += B("34", "12");            tmp += " A B" + A("12") + B(joint, "c") + A("34");        }


输出格式

会经过代码分析器分析为:

       public void Jump()        {            string tmp ="start ===\n";            string _result_6_ ="add a"+"12";            string _result_7_ ="add b\n";            string _result_8_ ="add a"+joint.format;            _result_7_ +=_result_8_+joint;            string _result_9_ ="add a"+"34";            tmp +=" A B"+_result_6_+_result_7_+_result_9_;         } 


思路

整体思路:

分治法。

每个函数有多行语句,每行语句包含多个函数,经过相互调用就相当于减了一层调用。无论有多少层调用,最终都可以解析为只包含一层可以输出的序列。

如 tmp += A(cc)

就会变为:

<<A相关的表达式,同时更新所有的输入为cc输出为_result_1_>>

Tmp += _result_1_;

  

1 将每个函数解析为结构FuncDesc, 存入一个整体的FUNC_DICT中。

class FuncDesc(object):  def __init__(self):    self.params_list = []    self.func_desc = []    self.func_desc_split = []    self.func_name = ""    self.out_name = ""

  

2 每个out_name和params_list的表示都用一个特殊的完全不同的字符串代替。方便以后在调用的时候,整体替换。

3 其中每个func_desc表示一行代码。

  每行代码再生成一个结构

class DescFuncSplit(object):  def __init__(self, desc_str):    self.desc_str = desc_str    # (type, funcname, params), type0:normal, 1 func    self.func_list = []    self.opeartor_list = []    self.has_semicolon = False

4 在调用到单个func_desc的时候,判断各个函数,调用到FuncDesc,赋值params和return_value。

  FuncDesc在依次调用每个func_desc_split。最终会得到一系列字符串。

  经过相互调用,最终会在最简单层中停止:

  code中A

这一系列的字符串就是最后希望得到的函数。

输出是最终的函数内部的内容。

需要自己加上函数头,可以放在C#编辑器里面format一下。

 

下附代码

#-*- coding:utf-8 -*-"""python XX.py inputfilename.cs out_func_name第一个参数是要读入的文件名称第二个参数是要输出的函数名"""import os, sysimport reTOTAL_NUM = 0;FUNC_DICT = {}def GetIndexNum():  global TOTAL_NUM  TOTAL_NUM += 1  return TOTAL_NUMdef replacer(search_obj, replace_str):  groups = search_obj.groups()  return groups[0] + replace_str + groups[1]   def change_descs(init_str, change_param, replace_param):  cal = r"(\W)%s(\W)" % change_param;  replacer2 = lambda search_obj: replacer(search_obj, replace_param)  return re.sub(cal, replacer2, init_str)   class DescFuncSplit(object):  def __init__(self, desc_str):    self.desc_str = desc_str    # (type, funcname, params), type0:normal, 1 func    self.func_list = []    self.opeartor_list = []    self.has_semicolon = False      def debug_info(self):    print "=============="    print "debug_info: ", self.desc_str    print self.func_list    print self.opeartor_list      def get_split_out_result(self, param_dict):    print "get_split_out_result" , param_dict    total_len = len(self.func_list)    out_str = ""    out_list = []    for idx in xrange(total_len):      func_tuple = self.func_list[idx]      if func_tuple[0] == 0:        out_str += func_tuple[1]      else:        func_result_name = "_result_%s_" % GetIndexNum()        func_desc = FUNC_DICT[func_tuple[1]]        params = func_tuple[2]        new_params = []        for new_param in params:          for k,v in param_dict.items():            new_param = new_param.replace(k, v)          new_params.append(new_param)                  tmp_list = func_desc.get_end_result(new_params, func_result_name)        out_list.extend(tmp_list)        out_str += func_result_name      if idx < total_len - 1:        out_str += self.opeartor_list[idx]    if self.has_semicolon:      out_str += ";"    out_str += "\n"    out_list.append(out_str)    return out_list        def tpl_func_split(self):    total_split = []    out_str = ""    if self.desc_str.find("+=") >= 0:      self.func_list.append((0, self.desc_str[:self.desc_str.find("+=")]))      out_str = self.desc_str[self.desc_str.find("+=") + 2:]      self.opeartor_list.append("+=")    elif self.desc_str.find("=") >= 0:      self.func_list.append((0, self.desc_str[:self.desc_str.find("=")]))      out_str = self.desc_str[self.desc_str.find("=") + 1:]      self.opeartor_list.append("=")    else:      out_str = self.desc_str        #鍘婚櫎瀛楃涓插唴閮ㄧ殑+ -> _    total_len = len(out_str)    idx = 0    while(idx < total_len):      if out_str[idx] == "\"":        idy = idx + 1        while(idy < total_len):          if out_str[idy] == "+":            out_str[idy] = "_"          if out_str[idy] == "\"":            idy += 1            break          idy += 1        idx = idy      else:        idx += 1        func_split = out_str.split("+")    for sp in func_split:      sp = sp.strip()      if sp[-1] == ";":        sp = sp[:-1].strip()        self.has_semicolon = True              if sp[0] == "\"":        self.func_list.append((0, sp))        self.opeartor_list.append("+")      elif sp[-1] == ")":        l = sp.find("(")        funcname = sp[:l].strip()        if not FUNC_DICT.has_key(funcname):          self.func_list.append((0, sp))          self.opeartor_list.append("+")          continue        params_str = sp[l+1:-1]        params_split = params_str.split(",")        params = []        for param in params_split:          param = param.strip()          params.append(param)        self.func_list.append((1, funcname, params))        self.opeartor_list.append("+")      else:        self.func_list.append((0, sp))        self.opeartor_list.append("+")    return            class FuncDesc(object):  def __init__(self):    self.params_list = []    self.func_desc = []    self.func_desc_split = []    self.func_name = ""    self.out_name = ""    def debug_info(self):    print "========"    print "params_list:", self.params_list    print "func_desc:"    print self.func_desc    print "func_name: %s, out_name: %s" % (self.func_name, self.out_name)      def get_func_name(self, fs):    fp = fs.split("(")    tmp_list = fp[0].split(" ")    self.func_name = tmp_list[-1];    fp[1] = fp[1].replace(")", "")    tmp_list = fp[1].split(",")      for tmp in tmp_list:      tt = tmp.split(" ")      for idtt in xrange(len(tt) - 1, -1, -1):        if tt[idtt].strip() != "":          self.params_list.append(tt[idtt].strip())             break            def change_params_to_unique(self):    for params_key in xrange(len(self.params_list)):      new_param = "_param_%s_" % GetIndexNum()      param = self.params_list[params_key]            self.params_list[params_key] = new_param      for desc_key in xrange(len(self.func_desc)):        desc = self.func_desc[desc_key]        new_desc = change_descs(desc, param, new_param)        self.func_desc[desc_key] = new_desc    return    def change_out_name_to_unique(self):    return_desc = self.func_desc[-1]    new_desc = return_desc.replace(";", "")    if new_desc.find("return") < 0:      return    out_name = new_desc[new_desc.find("return") + 6:].strip()    if out_name == "":      self.func_desc.pop()      return    self.out_name = "_result_%s_" % GetIndexNum()    for desc_key in xrange(len(self.func_desc)):      desc = self.func_desc[desc_key]      new_desc = change_descs(desc, out_name, self.out_name)      self.func_desc[desc_key] = new_desc    self.func_desc.pop()    return    def change_desc_value_to_func_split(self):    for desc in self.func_desc:      desc_func_split = DescFuncSplit(desc)      desc_func_split.tpl_func_split()      self.func_desc_split.append(desc_func_split)         def get_end_result(self, params, func_result_name):    print "get_end_result ", params, func_result_name    if self.out_name != "" and func_result_name == "":      print "error %s has no func_result_name" % self.func_name      raise 1    if len(params) != len(self.params_list):      print "error %s params error %s %s" % (self.func_name, self.params_list, params)      raise 1        param_dict = {}    for idx in xrange(len(self.params_list)):      param_dict[self.params_list[idx]] = params[idx]    out_list = []    for func_split in self.func_desc_split:      func_split.debug_info()      func_str_list = func_split.get_split_out_result(param_dict)      for func_str in func_str_list:        out_str = func_str;        for k,v in param_dict.items():          out_str = out_str.replace(k,v)        out_list.append(out_str)    if self.out_name != "":      for idx in xrange(len(out_list)):        out_str = out_list[idx]        out_list[idx] = out_str.replace(self.out_name, func_result_name)    return out_listdef main(filename, out_func_name):  f = open(filename, "r")  lines = f.readlines();  f.close();  total_line = len(lines)  for line in lines:    if line.startswith("{") or line.endswith("}"):      if len(line.strip()) != 1:        print "not strip one line", line        raise 1  cur_num = 0  while(cur_num < total_line):    if lines[cur_num].find("public") < 0:      cur_num += 1      continue    func_desc = FuncDesc()    func_desc.get_func_name(lines[cur_num])    cur_num += 1    while(cur_num < total_line):      if lines[cur_num].strip() == "{":        break      cur_num += 1          cur_num += 1    cur_left = 1    while(cur_num < total_line):      if lines[cur_num].strip() == "{":        cur_left += 1      if lines[cur_num].strip() == "}":        cur_left -= 1        if cur_left == 0:          break       strip_line = lines[cur_num].strip()      if strip_line != "" and not strip_line.startswith("//"):        func_desc.func_desc.append(lines[cur_num])      cur_num += 1    FUNC_DICT[func_desc.func_name] = func_desc    cur_num += 1    print FUNC_DICT.keys()    for func_desc in FUNC_DICT.values():    func_desc.change_params_to_unique()    func_desc.change_out_name_to_unique()    func_desc.change_desc_value_to_func_split()    func_desc.debug_info()    if not FUNC_DICT.has_key(out_func_name):    print "error outfuncname in readfile", filename    return    out_str_list = []  out_str_list = FUNC_DICT[out_func_name].get_end_result([], "")  f = open("out.txt", "w")  for out_str in out_str_list:    f.write(out_str)  f.close()   if __name__ == "__main__":  if len(sys.argv) < 3:    print "please input: readfilename outfuncname"    exit()  out_func_name = sys.argv[2]  filename = sys.argv[1]  main(filename, out_func_name)



0 0