0

I am working on an emulation tool in windows.

On intercepting an application I landed up with a situation.

I have a c++ structure which has the following format

typedef struct node {
  int open;
  int version;
  const unsigned long long * data;
  char* flags;
} _node;

It is a handle to a binary file. I am doing API interception and I get this pointer from an internal API call being made by the application.

Also The data field in the structure above is a pointer to instances of two structures laid out contiguously. The two structures are as follows.

typedef struct header{
  unsigned int open;
  unsigned int version;
  unsigned long long int length;
} _header;


typedef struct body{
  unsigned int v1, v2, v3, v4, v5, v6, v7, v8, v9, v10;
  unsigned long long int ll1, ll2;
} _body;

I am able to access and print the data field as follows.

_node* First=(node *)address;//Address is a pointer that i get from intercepting an application
_header* nodeHeader=(_header*)First->data;
char *bodyPtr=(char *)(nodeHeader+1);
_body* nodeBody=(_body *)(bodyPtr);
unsigned long long int offset=0;

while(!(nodeBody->v1 & 1) && offset< nodeHeader->length)
{
 nodeBody=(_body*)(bodyPtr+offset);
 offset=nodeBody->v2+nodeBody->v3;
}

I want to write the struct node instance into a text file and be able to read it back into a struct instance later. What is the best way to do it? I want an answer in c++

I want a c++ code because the code I am working on is in c++. The code i posted here has typedef because people who wrote the structure has written it in C.

If it would help, I need this data in the structure so I could emulate an application with my tool.Since some aspects of the structure are internal and are hidden from me, my best bet is to store the structure members and reconstruct it at a later time (emulation time)

ash
  • 1,170
  • 1
  • 15
  • 24
  • 2
    How do you even get `data` to point to an anonymous `struct` anyway? – Mark B Oct 10 '11 at 17:39
  • 1
    Did you want an answer in C++ or C? You should pick one really - the answers you will get for both are *very* different. – Flexo Oct 10 '11 at 17:40
  • @mark I have no idea! This is a struct I get by intercepting a program. I want to be able to use it. The entire structure basically is a handle to a binary format – ash Oct 10 '11 at 17:43
  • 4
    You want an answer in C++, yet you abuse an integer to hold two pointers? What sort of Wile E Coyote logic is that? – Kerrek SB Oct 10 '11 at 17:43
  • @awoodland I told I have a c++ struct. so I assumed people will give me a c++ answer! Anyway I added that I want a c++ solution to it. Thanks! – ash Oct 10 '11 at 17:43
  • @KerrekSB How much I would love to be able to answer that! Only that this is part of a mysterious binary which I intercepted from an application. – ash Oct 10 '11 at 17:44
  • 2
    You intercepted the data, but presumably, you wrote this code. Right? Because the code needs work before anyone can address the question I think. – Grumdrig Oct 10 '11 at 17:47
  • 1
    This code won't even compile. That makes this not a real question. I'm voting to close. – sbi Oct 10 '11 at 17:47
  • Guys hold on . I think I gave the wrong impression in the code I wrote. Let me elaborate. – ash Oct 10 '11 at 17:49
  • @Grumdrig I was lazy to mention the names of each of the 12 variables in the body struct and that gave us this confusion. Sorry about that – ash Oct 10 '11 at 17:53
  • 2
    @ash: It still doesn't compile. (`struct {} blah;` is not what you think it is.) – sbi Oct 10 '11 at 17:55
  • @sbi I am sorry but I dont understand your point. I have three structures. Struct node, struct header and struct body. What are you talking about here? – ash Oct 10 '11 at 17:57
  • That wasn't really the concern, at least for me. I understood your pseudocode at least as well as I understand it now. Don't you need some real code if you're ever going to save and load this data? Why not start from there? – Grumdrig Oct 10 '11 at 17:57
  • @ash: I am talking about you _not_ having three structs `node`, `header`, and `body`. `struct {} blah;` does _not_ define a struct `blah`. (And you don't need to write `struct blah` in C++ either, that's a C-ism. Just `blah` will do. You might want to read [a good C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list).) – sbi Oct 10 '11 at 17:59
  • 1
    @ash: If you were really lazy, and had compiling code, you'd have copy and pasted it into the question, and we'd have more to go on. What we typically need is the actual code, not a quickly typed in look-alike. Moreover, you need to be more specific on what `data` points to. Is it a pointer to a struct that has another one immediately following, or more complicated? – David Thornley Oct 10 '11 at 18:03
  • @sbi I am sorry for being clumsy with the syntax. But I have a problem of overlooking obvious issues and getting to the point. Guess I am not the person to articulate things. But still that shouldnt have stopped you form answering the question after a reprimand at best! anyways thanks for the help – ash Oct 10 '11 at 18:05
  • @DavidThornley hope my edits de mystify my shoddy pseudo code! – ash Oct 10 '11 at 18:23
  • You want an answer in C++, but you typedef your structs? What sort of Daffy Duck logic is that? – Kerrek SB Oct 10 '11 at 18:44
  • 3
    @ash: Don't mangle the post then re-post it elsewhere. Edit it to make sense, then people will vote to re-open. – Lightness Races in Orbit Oct 10 '11 at 18:44
  • Since so many people have spent energy trying to make this question work, I went ahead and ... fitted boost on it. Mainly just because I needed exercise with boost serialization :_) – sehe Oct 10 '11 at 21:49

1 Answers1

0

I'm not sure I'm not getting the entire question context right, but here is a setup based on boost serialization:

Of course I opted for the C++ way

  • using a std::pair or std::tuple to model a contiguously stored pair of structs (see element_t). 2
  • I would actually prefer using a list of element_t instead of element_t*. Regardless, it works both ways with this library
  • I chose XML for clarity: the sample clearly shows what gets serialized and how duplicate (aliased) pointers get correctly treated and restored.
  • simple drop-in replacement for binary serialization instead of XML if preferred: s/xml_/binary_/g does the trick! 1
    You could also drop the NVL() macros because binary serialization doesn't need named elements:

     ar & NVP(version) & NVP(open) & NVP(length);
    

    would become

     ar & version & open & length;
    

  • as written, the sample leaks the data elements (just a demo, and I was trying several things; I decided on using pointers only to match your question more closely)

1 oops, almost forgot about std::ios:binary on opening you fstreams!
2Note that for particular in-memory layout you may need to tinker with a struct using #pragma to achieve proper aligment/padding. That is beyond the scope of my answer

Oh, compile with

g++ -O2 -g test.cpp -lboost_serialization

Tested with boost v.1_42 through boost v.1_47


#include <boost/serialization/list.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <fstream>
#include <string>

#define NVP BOOST_SERIALIZATION_NVP // name-value pairs

struct header
{
    unsigned int open;
    unsigned int version;
    unsigned long long int length;

    header() : open(1), version(2), length(3) {} 

private:
    friend class boost::serialization::access;
    template<class Archive>
        void serialize(Archive & ar, const unsigned int archversion)
    {
        ar & NVP(version) & NVP(open) & NVP(length);
    }
};

struct body
{
    unsigned int iv[20];
    unsigned long long int ll1, ll2;

    body() : ll1(1), ll2(2)
    {
        for (int i=0; i<20; i++)
            iv[i] = i;
    }

private:
    friend class boost::serialization::access;
    template<class Archive>
        void serialize(Archive & ar, const unsigned int archversion)
    {
        ar & NVP(ll1) & NVP(ll2) & NVP(iv);
    }
};

typedef std::pair<header, body> element_t;

struct node
{
    int open;
    int version;
    std::list<element_t*> data;
    std::string flags;

    node() : open(1), version(2), flags("hello") { }

private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int archversion)
    {
        ar & NVP(version) & NVP(open) & NVP(flags) & NVP(data);
    }
};

int main()
{
    node anode;
    anode.data.push_back(new element_t(header(), body()));
    element_t* duplicated = new element_t(header(), body());
    anode.data.push_back(duplicated);
    anode.data.push_back(new element_t(header(), body()));
    anode.data.push_back(duplicated);

    {
        std::ofstream ofs("/tmp/test.xml");
        boost::archive::xml_oarchive archive(ofs);

        archive << NVP(anode);
        ofs.flush();
        ofs.close();
    }
    return 0;

    {
        std::ifstream ifs("/tmp/test.xml");
        boost::archive::xml_iarchive archive(ifs);

        node deserialized;

        archive >> NVP(deserialized);
    }

    return 0;
}

Here is the sample output (test.xml)

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="9">
<anode class_id="0" tracking_level="0" version="0">
    <version>2</version>
    <open>1</open>
    <flags>hello</flags>
    <data class_id="1" tracking_level="0" version="0">
        <count>4</count>
        <item_version>0</item_version>
        <item class_id="2" tracking_level="1" version="0" object_id="_0">
            <first class_id="3" tracking_level="0" version="0">
                <version>2</version>
                <open>1</open>
                <length>3</length>
            </first>
            <second class_id="4" tracking_level="0" version="0">
                <ll1>1</ll1>
                <ll2>2</ll2>
                <iv>
                    <count>20</count>
                    <item>0</item>
                    <item>1</item>
                    <item>2</item>
                    <item>3</item>
                    <item>4</item>
                    <item>5</item>
                    <item>6</item>
                    <item>7</item>
                    <item>8</item>
                    <item>9</item>
                    <item>10</item>
                    <item>11</item>
                    <item>12</item>
                    <item>13</item>
                    <item>14</item>
                    <item>15</item>
                    <item>16</item>
                    <item>17</item>
                    <item>18</item>
                    <item>19</item>
                </iv>
            </second>
        </item>
        <item class_id_reference="2" object_id="_1">
            <first>
                <version>2</version>
                <open>1</open>
                <length>3</length>
            </first>
            <second>
                <ll1>1</ll1>
                <ll2>2</ll2>
                <iv>
                    <count>20</count>
                    <item>0</item>
                    <item>1</item>
                    <item>2</item>
                    <item>3</item>
                    <item>4</item>
                    <item>5</item>
                    <item>6</item>
                    <item>7</item>
                    <item>8</item>
                    <item>9</item>
                    <item>10</item>
                    <item>11</item>
                    <item>12</item>
                    <item>13</item>
                    <item>14</item>
                    <item>15</item>
                    <item>16</item>
                    <item>17</item>
                    <item>18</item>
                    <item>19</item>
                </iv>
            </second>
        </item>
        <item class_id_reference="2" object_id="_2">
            <first>
                <version>2</version>
                <open>1</open>
                <length>3</length>
            </first>
            <second>
                <ll1>1</ll1>
                <ll2>2</ll2>
                <iv>
                    <count>20</count>
                    <item>0</item>
                    <item>1</item>
                    <item>2</item>
                    <item>3</item>
                    <item>4</item>
                    <item>5</item>
                    <item>6</item>
                    <item>7</item>
                    <item>8</item>
                    <item>9</item>
                    <item>10</item>
                    <item>11</item>
                    <item>12</item>
                    <item>13</item>
                    <item>14</item>
                    <item>15</item>
                    <item>16</item>
                    <item>17</item>
                    <item>18</item>
                    <item>19</item>
                </iv>
            </second>
        </item>
        <item class_id_reference="2" object_id_reference="_1"></item>
    </data>
</anode>
sehe
  • 374,641
  • 47
  • 450
  • 633
  • The structs from the OP can't be changed because they come from an external (intercepted) API like that, from what I understand. – Xeo Oct 10 '11 at 22:22
  • I appreciate the effort but as Xeo had pointed out the structure cannot be changed. I got it by intercepting the application at runtime. – ash Oct 10 '11 at 22:31
  • @Xeo note that you don't _have to_ modify any structs. My sample is closely based on them, mostly modifying them in order to compile. I'll leave adapting/integrating up to the OP. – sehe Oct 10 '11 at 22:34
  • To point out the obvious: you can add serialization to any odd (POD) structure in this way. (optionally derive from them to keep headers clean) – sehe Oct 10 '11 at 22:37