【问题标题】:Reading data file, structure of data obtained with GDB from an elf file读取数据文件,使用 GDB 从 elf 文件中获取的数据结构
【发布时间】:2022-01-02 15:09:34
【问题描述】:

我有一个来自游戏的数据文件“tasks.data”,我想读取它。

从游戏“tasks.so”的 ELF 文件中,我使用 GDB、gdb ptype 等获得了数据结构

在我找到一些我认为我没有正确读取的矢量类型之前,我正在读取文件而没有问题正确获取字段。

来自 gdb 的部分结构:

..etc...
....
bool m_bOnFailPopup;
unsigned int m_ulOnFailSoundID;
unsigned int m_ulOnFailGfxID;
unsigned int m_ulNextSibling;
unsigned int m_ulFirstChild;
std::wstring m_wstrName;
std::wstring m_wstrNameSuffix;
std::wstring m_wstrDescript;
std::wstring m_wstrOnNewTribute;
std::wstring m_wstrOnNewConfirm;
std::wstring m_wstrOnCompleteConfirm;
std::wstring m_wstrMethodTrace;
std::wstring m_wstrMethodString;
std::wstring m_wstrCategory;
std::wstring m_wstrUnitProtectWarning;
std::wstring m_wstrUnitProtectFailed;
talk_proc m_DelvTaskTalk;
talk_proc m_AwardTalk;

//until here I can read without problems, I read the bytes and get the data

//here are this others vector things that I not sure I am reading correctly

std::vector<TaskSimpleCondition, std::allocator<TaskSimpleCondition> > m_vetPremSimple;
std::vector<TASK_OPEN_TIME, std::allocator<TASK_OPEN_TIME> > m_vetOpenTime;
std::vector<ITEM_WANTED, std::allocator<ITEM_WANTED> > m_vetPremItems;
std::vector<short, std::allocator<short> > m_vetPremTitles;
std::vector<REPU_WANT, std::allocator<REPU_WANT> > m_vetPremRepu;

我为此使用 python,我读取文件转到此数据开始的偏移量,读取字节显示 int 或解码它的文本是一个字符串。 我从 GDB 获得的结构在 python 中解析,不用作类或任何东西。我解析结构的每一行,获取 varname、vartype 并根据它的内容读取字节。

例如,如果它是“bool varname”,我读取 1 个字节并获取 int 并继续下一个结构行。

那些 std::vector 行我也在做同样的事情:

例子

std::vector<TaskSimpleCondition, std::allocator<TaskSimpleCondition> > m_vetPremSimple;

我正在阅读,好像它在哪里:

TaskSimpleCondition m_vetPremSimple;

我得到“TaskSimpleCondition”的结构,并为每一行读取它的字节。

事情在该行下方,我开始得到时髦的数据,所以可能我读错了。

所以主要问题是:我应该如何处理 std::vector 行?该向量是否是库的内部事物,与从 data.file 读取的数据无关?

在其名称为 (ATaskTempl) 的主结构的末尾我也有这行,我暂时忽略它

...etc...
ATaskTempl *m_pParent;
ATaskTempl *m_pPrevSibling;
ATaskTempl *m_pNextSibling;
ATaskTempl *m_pFirstChild;)

因为它会导致无限循环,所以它会在最后获得 ATaskTempl 的结构,另一个子 var 将获得相同的结构,依此类推。

有人可以指导我吗?

我在 python 中写这个,我使用的结构来自一个用 GDB 读取的 ELF 文件。

最后一件事,我有一些结构说:

type = struct CLASSNAME : ANOTHER_CLASSNAME {
    data.....

在这些情况下,我正在做的是获取第二类结构,并添加第一类结构。对吗?

【问题讨论】:

  • 向量不是简单的类型。它们不仅使用动态分配的内存,即使您只想要该类的基本部分,除非您使用与之前使用的完全相同的 stl 版本,您要求 ub。因为布局可能会改变。

标签: c++ struct gdb


【解决方案1】:

我有一个来自游戏的数据文件“tasks.data”,我想读取它。

为此,您需要了解如何存储数据。

从游戏“tasks.so”中我得到了使用 GDB 的数据结构

极不可能你得到的结构是实际保存在磁盘上的(它很可能用于表示数据在内存中,但它只是不能表示磁盘上的数据)。

该结构包含std::wstrings,它将包含指向数据而不是实际数据的指针(至少对于足够长的字符串而言)。

它还包含std::vectors,它总是包含指针而不是实际数据。

例如,如果它是“bool varname”,我读取 1 个字节并获取 int 并继续下一个结构行。

这也是不正确的,除非结构有__attribute__((packed))——bool 和下面的int 之间应该有一个填充间隙。

所以主要问题是:我应该如何处理 std::vector 线?

您必须对tasks.so 库进行逆向工程以了解如何它将std::vectors 存储在磁盘上,然后应用逆向转换从磁盘上恢复内存中的视图查看。

这是向量存储在磁盘上的一种方式(但不一定是tasks.so 的方式):

// returns number of bytes stored, or -1 on error.
ssize_t save_vec(const std::vector<short>& v, FILE *out)
{
  const size_t size = v.size();
  if (1 != fwrite(&size, sizeof(size_t), 1, out)) return -1;
  if (size != fwrite(v.data(), sizeof(v[0]), size, out)) return -1;
  return sizeof(size) + size * sizeof(v[0]);
}

要反转上述转换,您将(显然)读取大小,创建适当大小的向量,然后将实际数据读入其中。

【讨论】:

  • 感谢您的回答,我将尝试使用 ghidra 或其他工具读取 libtask.so 以查看是否可以找到读取 tasks.data 文件的部分
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-30
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多