在逆向工程工业机器人软件以获得一些值时遇到麻烦

逆向工程 艾达 C++ C 静态分析
2021-07-02 21:15:26

关于背景,我是一名机器人工程师。机器人制造商隐藏了他们机器人的一些参数,以避免他们的竞争。现在,我需要这些数据来计算机器人的动力学模型。我正在努力在能源消耗方面建立一个理想的“探路者”。

基本上,我有一个 .dat 文件,收集了我想要的所有参数,但我不知道“哪个”是“哪个”。

我已经从机器人上复制了代码并使用 Ida pro 对其进行了反汇编。现在,我有一些我分析的伪代码。

  FILE *__cdecl CDynamicData::loadRobcorFile(CDynamicData *this, char 

*filename, unsigned __int16 a3)
{
  int v3; // eax@4
  const char *v4; // ebx@6
  int v5; // eax@6
  signed int v6; // edx@6
  int v7; // eax@7
  int v8; // eax@8
  const char *v9; // ebx@11
  int v10; // eax@11
  signed int v11; // edx@11
  int v12; // eax@12
  int v13; // eax@13
  signed int v14; // ebx@16
  int v15; // eax@16
  signed int v16; // edx@16
  int v17; // eax@19
  signed int v18; // edx@19
  int v19; // eax@20
  int v20; // eax@25
  int i; // esi@28
  float v22; // ST34_4@31
  int v23; // eax@32
  int v24; // edi@34
  int v25; // esi@35
  float v26; // ST34_4@38
  FILE *result; // eax@41
  int v28; // [sp+28h] [bp-400h]@27
  int nbParam; // [sp+2Ch] [bp-3FCh]@27
  int v30; // [sp+30h] [bp-3F8h]@34
  char s; // [sp+40h] [bp-3E8h]@29
  char src; // [sp+140h] [bp-2E8h]@4
  char v33; // [sp+240h] [bp-1E8h]@30
  int v34; // [sp+340h] [bp-E8h]@23
  int v35; // [sp+3A0h] [bp-88h]@23
  char v36; // [sp+3B8h] [bp-70h]@23
  char v37; // [sp+3C0h] [bp-68h]@23
  char v38; // [sp+3C8h] [bp-60h]@23
  int v39; // [sp+3D4h] [bp-54h]@23
  FILE *stream; // [sp+3ECh] [bp-3Ch]@1
  void *v41; // [sp+3F0h] [bp-38h]@1
  int v42; // [sp+3F4h] [bp-34h]@1
  double v43; // [sp+3F8h] [bp-30h]@23
  double value; // [sp+400h] [bp-28h]@29
  int v45; // [sp+408h] [bp-20h]@4
  int indice; // [sp+40Ch] [bp-1Ch]@27
  int v47; // [sp+410h] [bp-18h]@25
  int v48; // [sp+414h] [bp-14h]@32

  stream = 0;
  v42 = 256;
  readIntValues((CFileParser *)&stream, "$DYN_DAT", "REAL $DYN_DAT[%d]", &src, 1, &v47);
  v20 = operator new[](8 * v47, &std::nothrow);
  *((_DWORD *)this + 3) = v20;


  v28 = *((_DWORD *)this + 3);
  nbParam = v47;
  indice = 0;
  if ( v47 > 0 )
  {
    i = 0;
    do
    {
      CFileParser::getLine((CFileParser *)&stream, &s);
      if ( sscanf(&s, "$DYN_DAT[%d]=%lf", &indice, &value) != 2 )

      { // Can't acquire data
        snprintf(&v33, 0x100u, "%s konnte nicht gelesen werden", "$DYN_DAT[%d]=%lf");
        extended_internalError(
      }
      v22 = value;
      *(double *)(v28 + 8 * indice - 8) = v22;
      ++i;
    }
    while ( nbParam != i );
  }

基本上,我不明白以下含义:

  *((_DWORD *)this + 3) = v20;

和:

      *(double *)(v28 + 8 * indice - 8) = v22;

你有什么想法 ?

到目前为止,我认为它是一个指针指针,但我不明白它的“含义”,因为看起来 v28 是一个具有未分配空间的“局部变量”?

这是对象 DynDat 的构造函数的“伪代码”:

int __cdecl CDynamicData::CDynamicData(int a1)
{
  int result; // eax@1

  result = a1;
  *(_BYTE *)a1 = 0;
  *(_DWORD *)(a1 + 4) = 0;
  *(_DWORD *)(a1 + 8) = 0;
  *(_DWORD *)(a1 + 12) = 0;
  return result;
}

附加问题:您是否知道追溯某些值的解析和使用的最有效方法?

亲切的问候,

2个回答

v20 的东西只是 this->mem = new(); 这是某种结构

您发布的动态数据构造函数实际上是用 0 填充结构

您需要将 int a1 更改为 struct foo* a1

在此之前,您需要在 ida 中定义结构

因此,由于它返回结构指针,因此您需要将返回值也更改为 struct foo*

尝试编译此代码并在 ida 中反编译它,您将看到反编译与您发布的完全相似

#include <stdio.h>
#include <memory.h>

typedef struct _SOMESTRUCT {
    unsigned int a;
    unsigned int b;
    unsigned int c;
    unsigned int d;
}Sostr,*PSostr;

PSostr foo( PSostr blah) {

    blah->a = 0;
    blah->b = 0;
    blah->c = 0;
    blah->d = 0;
    return blah;
}

int main (void)
{
    Sostr temp = {0xdeadbeef,0xdeadbeef,0xdeadbeef,0xdeadbeef};    
    printf("%08x %08x %08x %08x\n" , temp.a,temp.b,temp.c,temp.d);
    foo(&temp);
    printf("%08x %08x %08x %08x\n" , temp.a,temp.b,temp.c,temp.d);
    return 0;    
}

谷歌搜索 $DYN_DAT 似乎会产生很多信息,包括一个 .dat 文件,其数据显示 $DYN_DAT[] 是一个浮点数/双精度数组

所以基本上它打开文件并检查第一个条目 $REAL_DYN_DAT[XXX] 其中 XXX 是所有 $DYN_DAT 条目的大小

分配 XXX * 8 大小的内存逐行解析 $DYN_DAT 条目并存储它读取的所有 Double 值

该文件看起来像这样

REAL $DYN_DAT[xxx] this is the size of all $DYN_DAT
$DYN_DAT[1]=0.xxxxx
$DYN_DAT[2]=0.yyyyy
$DYN_DAT[3]=1.zzzzz
$DYN_DAT[4]=1.aa
$DYN_DAT[5]=0.mmmm ........ $DYN_DAT[xxx} = d.efghijk

很抱歉在“答案”部分发帖(但我不能在没有声誉的情况下发表评论 >= 50)

所以在使用谷歌一段时间后,我的知识是:它是一个 KUKA 机器人,$DYN_DAT 是 $robocor.dat(还包含其他数组/变量)的一部分 - http://www.wtech.com.tw/public/download /manual/kuka/krc2/System_Variables_manual.pdf:“包含机器人的模型数据,这些数据是加速度适应、更高的运动曲线和动能计算(惯性矩、摩擦值等)所需的”所以$DYN_DAT 是一个 REAL 数组,也就是 double/float64 值,其中一些是已知的 - 可以通过结合在互联网上传播的多个文档来推断,我不清楚 $DYN_DAT 数组是否对每种类型的 KUKA 都具有相同的意义机器人

我知道 $DYN_DAT 的内容没有完整记录,这就是你想要的

问题:

给定的反编译(总是对 hex-rays 结果印象深刻)代码看起来像一个文本文件解析器或其他东西,我不认为解析文本文件是你的问题,或者?您能否向我们提供 $robocor.dat (pastebin.com) 的样本以明确我们真正要基于的内容

想法:

如果我是对的(并且它是一个文本文件并且解析没有问题),接下来将找出谁使用了 $DYN_DAT 的哪些部分:

有几种“攻击策略”可用,但“我已经从机器人复制代码并进行了分解”让我有点困难

  1. 定义一个带有伪类的 c-header,可以使用 File/Load 文件将其加载到 IDA 中,您可以使用伪类构建测试项目,以查看内存布局是否适合反向代码中的
  2. 这是否意味着您无法调试在 IDA 中运行的代码
  3. 是否有可以在纯 Windows 或 Linux 上运行的仿真系统?
  4. 哪些工具在使用 $robocore/$DYN_DAT - 也许是更简单的教学工具或者更容易逆转的东西
  5. 32 或 64 位 - 我认为您的代码是 32 位

疯狂的想法:一个小的挑战主页怎么样,选择 KUKA/Robot-Types,逐行显示您当前对 $DYN_DAT 的知识,添加上传 $robocor.dat 文件的能力 - 让它成为一个人群问题,发布它在 reddit/serveral KUKA 论坛上,从其他人那里获得更快的信息

关于 C++ 逆向的漂亮小教程 https://blog.0xbadc0de.be/archives/67

内存布局描述等

static_assert(sizeof(int) == 4, "wrong size"); // are we 32bit
typedef unsigned int _DWORD;
static_assert(sizeof(double*) == sizeof(_DWORD));

//1. find allocation(new) of CDynamicData then you know how many (vtable+)member-bytes the class containts
// give IDA a header with the class then is hex-rays able to give you even better results

#pragma pack(push,1)
class CDynamicData
{
public:
    //already known
    unsigned char unknown0 = 0;
    unsigned char unknown1 = 0;
    unsigned char unknown2 = 0;
    unsigned char unknown3 = 0;
    _DWORD unknown4 = 0;
    _DWORD unknown5 = 0;
    double* dyn_dat_values = nullptr;
    //unsigned char unknown6[x] -> fill that up

    CDynamicData()
    {
       unknown0 = 0;
       unknown4 = 0;
       unknown5 = 0;
       dyn_dat_values = 0;
    }
};
#pragma pack(pop)

void test()
{
    assert(offsetof(CDynamicData, dyn_dat_values) == 12);

    CDynamicData dd;
    void* _this = &dd;

    int v42 = 123456; // readIntValues...

    double* v20 = new (std::nothrow) double[v42];

    //*((_DWORD *)this + 3) = v20;
    assert((char*)&dd.dyn_dat_values == (char*)((_DWORD *)_this + 3));
    dd.dyn_dat_values = v20;

    double* v28 = dd.dyn_dat_values; // in code a int --> int == ptr-value

    double v22 = 123456.0; // scanf...
    //*(double *)(v28 + 8 * indice - 8) = v22;
    //start with pointer to double array, + 8 because of sizeof(double), -8 because of indice starting with 1 not 0
    int indice = 1; //= 1..n
    v28[indice - 1] = v22;
}

当心认为 int 意味着值 - hex-rays 输出是高级别 asm 所以每个 int 也可能只是一个指向某物的指针

加载 C 头文件:https : //www.hex-rays.com/products/ida/support/idadoc/1367.shtml 我为 IDA 准备了这个头文件:https : //pastebin.com/PWNAAj7T,在分析前加载和十六进制射线,然后你会更清楚地看到发生了什么

然后跟踪 CDynamicData 的每次出现并告诉 IDA 使用您的结构类型 - 这将有很大帮助