天马阁

 找回密码
 立即注册
                                        →→→→→→→→→→→→ 1点击查看所有VIP教程目录长列表(总教程数269个) 2办理VIP详情进入 ←←←←←←←←←←←←
1 x64CE与x64dbg入门基础教程 7课 已完结 2 x64汇编语言基础教程 16课 已完结 3 x64辅助入门基础教程 9课 已完结 4 C++x64内存辅助实战技术教程 149课 已完结
5 C++x64内存检测与过检测技术教程 10课 已完结 6 C+x64二叉树分析遍历与LUA自动登陆教程 19课已完结 7 C++BT功能原理与x64实战教程 29课 已完结 8 C+FPS框透视与自瞄x64实现原理及防护思路 30课完结
64驱?封? 9 64反驱? 10 64位V? 11 绝? 12 ???课?
13 64透 ? 14 64U ? 15 64Q ? 16 64功 ?
17 64U ? 18 64模 ? 19 64多 ? 20 64网 ?
21 64注 ? 22 64火 ? 23 64棋 ? 24 64自二链L?
25 64破 ? VIP会员办理QQ: 89986068   
【请先加好友,然后到好友列表双击联系客服办理,不然可能无法接受到信息。】
27 加入2000人交流群637034024 3 28 免责声明?
查看: 6386|回复: 0

详解定位特征码方法附带源码

[复制链接]

10

主题

0

回帖

12

积分

编程入门

Rank: 1

天马币
20
发表于 2024-3-6 09:14:59 | 显示全部楼层 |阅读模式

1、定位特征码的原因   
      无论破解还是做其他与逆向相关的东西,可能都需要定位特征码,使用绝对地址记住函数地址或者全局变量时,如果对应程序更新后,这个地址就无效了。此时可以通过特征码的方式定位它们,从而减少地址无效的概率。

    2、定位特征码的方法
    定位特征码的关键是找到的特征码随目标程序的更新而不改变。但是前提是特征码在对应DLL或者EXE文件中是唯一的。

    1)如果特征码的代码带有特殊的常量,并且这个常量不是目标程序的内存地址时,优先选取其为特征码。一般常量在程序中很少会改变。


例如如下为某函数的反汇编代码,获取这个函数的地址,选取"83 FE 2E 74 38"为特征码是比较合适的。-5地址处就为函数起始地址。

  $-5      > .  56            PUSH ESI                            ;函数地址     
  $-4      > .  8B7424 08     MOV ESI,DWORD PTR SS:[ESP+8]
  $ ==>    > .  83FE 2E       CMP ESI,2E        ;2e 为特殊常量
  $+3      > .  74 38         JE 0BCCCCA2        ;短跳转
  $+5      > .  83FE 2D       CMP ESI,2D        
  $+8      > .  74 33         JE 0BCCCCA2
  $+A      > .  83FE 33       CMP ESI,33

    2)如果特征码带有短跳转的代码,优先选取。因为只要你选取的特战码以及从选取的特征码地址到跳转的地址之间随目标程序更新变化的概率较少。如上面的短跳转指令

    3)如果特征码带有结构体或者类变量的对应偏移的代码,可以选取。一般只要结构体或者类变量不增加成员,就不会改变。

    例如如下代码,要获取全局变量 "106d83b8"的地址,选取"88 46 40 74 45"  为特征码是比较合适的。+0x22偏移处就为目标全局变量地址。
   
  $ ==>    >  8846 40         MOV BYTE PTR DS:[ESI+40],AL          ;结构体成员变量
  $+3      >  74 45           JE 10572F00        ;短跳转指令
  $+5      >  8B11            MOV EDX,DWORD PTR DS:[ECX]
  $+7      >  8B42 30         MOV EAX,DWORD PTR DS:[EDX+30]
  $+A      >  53              PUSH EBX
  $+B      >  8B1D AC406E10   MOV EBX,DWORD PTR DS:[106E40AC]
  $+11     >  FFD0            CALL EAX
  $+13     >  83BB E4010000 0>CMP DWORD PTR DS:[EBX+1E4],0
  $+1A     >  894424 18       MOV DWORD PTR SS:[ESP+18],EAX
  $+1E     >  74 29           JE 10572EFF
  $+20     >  8B0D B8836D10   MOV ECX,DWORD PTR DS:[106D83B8]    ;目标全局变量
  
    4)如果特征码位置,没有以上代码,可以采用特殊指令,不带有绝对地址的代码为特征码。

  下面是某个程序的消息处理函数的代码,可以采用"53 55 8B 6C 24 2C 56 57 FF D2"为特征码。
  $-19     >/$  83EC 20       SUB ESP,20                              
  $-16     >|.  A1 6881E40B   MOV EAX,DWORD PTR DS:[BE48168]
  $-11     >|.  33C4          XOR EAX,ESP
  $-F      >|.  894424 1C     MOV DWORD PTR SS:[ESP+1C],EAX
  $-B      >|.  8B0D 6007EA0B MOV ECX,DWORD PTR DS:[BEA0760]
  $-5      >|.  8B01          MOV EAX,DWORD PTR DS:[ECX]
  $-3      >|.  8B50 0C       MOV EDX,DWORD PTR DS:[EAX+C]
  $ ==>    >|.  53            PUSH EBX        ;特征码
  $+1      >|.  55            PUSH EBP
  $+2      >|.  8B6C24 2C     MOV EBP,DWORD PTR SS:[ESP+2C]
  $+6      >|.  56            PUSH ESI
  $+7      >|.  57            PUSH EDI
  $+8      >|.  FFD2          CALL EDX

    3、定位特征码注意事项
    1) 特征码中不能带有绝对地址。
   2)特征码必须在对应模块中是唯一的,否则搜索到的特征码地址可能是错误的。

    4、搜索特征码
     下面是我之前写的搜索特征码的代码,可以参考。

// ==========================================================
// 函数名称:SearchDataFromProcess
// 函数用途:从指定模块中搜索指定字节集的数据
// 输入参数:BYTE* pSearch      要搜索的字节集
//     int size        要搜索字节集的大小
//                dllName                                                 要搜索的模块名
// 返    回:搜索到的进程地址
// ==========================================================
int SearchDataFromProcessByDllName(BYTE* pSearch, int size, char* dllName)
{
  int i,j;
  DWORD OldProtect;
  BYTE* pOrg;
  BYTE* pPare;
  MODULEINFO mMoudleInfo;
  HMODULE  hMoudle;


  //获取模块地址
  hMoudle = GetModuleHandle(dllName);
  if(NULL == hMoudle)
  {
    hMoudle = LoadLibraryA(dllName);
    if(NULL == hMoudle)
    {
      return 0;
    }
  }

  pOrg = (BYTE*)hMoudle;
  

  //更改模块保护属性
  VirtualProtectEx(GetCurrentProcess(), hMoudle,1,PAGE_EXECUTE_READWRITE,&OldProtect);
  
  //得到模块大小
  GetModuleInformation(GetCurrentProcess(), hMoudle,&mMoudleInfo,sizeof(mMoudleInfo));

  //查找指定字节集
  for(i = 0; i <(int) mMoudleInfo.SizeOfImage; i++)
  {
    pPare =pOrg + i;

    for(j = 0; j < size; j++)
    {
      if(pPare[j] !=   pSearch[j])
      {
        break;
      }
    }
    //如果找到则返回找到的首地址
    if(j == size)
    {
      VirtualProtectEx(GetCurrentProcess(), hMoudle,1,OldProtect,NULL);

      return (int)(pPare);
    }
  }
  
  //直接退出
  VirtualProtectEx(GetCurrentProcess(), hMoudle,1,OldProtect,NULL);  
  return 0;
}

// ==========================================================
// 函数名称:GetFunAddr
// 函数用途:得到某函数地址
// 输入参数:NONE
// 返    回:NONE
// ==========================================================
/*
$-5      > .  56            PUSH ESI                                 
$-4      > .  8B7424 08     MOV ESI,DWORD PTR SS:[ESP+8]
$ ==>    > .  83FE 2E       CMP ESI,2E
$+3      > .  74 38         JE SHORT xx.0BCCCCA2
$+5      > .  83FE 2D       CMP ESI,2D
$+8      > .  74 33         JE SHORT xx.0BCCCCA2
$+A      > .  83FE 33       CMP ESI,33
83 FE 2E 74 38
-5
*/
bool GetFunAddr(void)
{
  int Addr;
  BYTE Data[]={0x83 ,0xFE ,0x2E ,0x74 ,0x38};

  //搜索特征码
  Addr = SearchDataFromProcessByDllName(Data, sizeof(Data), "xx.dll");      
  
  //判断是否查找到特征码
  if( 0 == Addr)
  {
    return false;
  }
  
  //取特征码
  g_Addr_Function = Addr - 0x05;
  
  return true;
}

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

天马阁|C/C++辅助教程|安卓逆向安全| 论坛导航|免责申明|Archiver||网站地图
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表天马阁立场!
任何人不得以任何方式翻录、盗版或出售本站视频,一经发现我们将追究其相关责任!
我们一直在努力成为最好的编程论坛!
Copyright© 2010-2021 All Right Reserved.
快速回复 返回顶部 返回列表