Giter VIP home page Giter VIP logo

c2py's Introduction

C2Py Struct Converter

Import memory dumps to Python classes generated according to defined C-structs, accelerating debugging and automation testing.

What does it do?

C2Py is here to help you convert your C structs and unions to Python classes with the same fields, names types and everything! That's not all though. C2Py can receive a buffer of bytes or memory dumps to assign to the struct's fields!

Why use it?

This project could be most likely be used for automation testing for C projects. Another use is perhaps debug - reading and understanding a memory dump better by importing it to readable struct-like classes.

Installation

This package requires Python 3.* Simply download this project, open cmd or terminal and enter:

  python /path/to/C2Py/setup.py install

And you're done!

Usage & Examples

As mentioned in before, this package is to assist C developers use the ctypes module by automatically parsing (and populating) their structs. This is done simply by providing the source files (intermediate files or *.i files - more on that later) and (optional) binary data files or byte arrays to provide data to assign to the parsed structs/unions.

struct my_struct {
  int a;
  char c;
};
...

// Instance of my_struct, later saved into a binary file
struct my_struct instance;
instance.a = 5;
instance.c = 'o';

And the conversion (assuming there's a binary file with saved data from mentioned C struct):

import C2PyHandler
binary_file_handler = C2PyHandler.DefaultBinaryFileC2PyHandler("path\\to\\SourceIntermediate.i", "path\\to\\binaryfile")
result_struct = binary_file_handler.convert(struct_declaration="my_struct")
print(result_struct.a) # Prints 5
print(result_struct.b) # Prints 'o'

The API is quite simple:

  1. Create a new instance of the handler of you choice:
  • DefaultBinaryFileC2PyHandler - For populating the converted structs with data from binary files.
  • DefaultNoBufferC2PyHandler - For creating converted structs with all values initialized as 0.
  • DefaultRuntimeBufferC2PyHandler - For populating the converted structs with data provided at runtime (preferably via 'bytearray')
  • Create your own custom handler by overriding the "abstract" 'C2pyStructsAbsHandler'. This class has one unimplemented method: '_read_from_memory', which one must override should one write a custom handler.
  1. Call the 'convert' method with the proper parameters. Do note that different parameters may be required, depending on the handler used.

For more examples and how-to's please refer to the test.py module and source code found in the 'tests' directory.

Intermediate files C2Py could receive .h or .c files, but it works best with .i files. This is because C2Py does not parse macros (#define ...), but intermediate files, or preprocessed files, are files which are generated during compilation and deleted afterwards. They aren't normally used by the average C developer. Don't worry if you've never heard of them (I haven't till I started working on this project). All you need to do is add a flag to your compilation process to keep these files. If you're using gcc you may use the Makefile under 'tests' for reference.

Tests

All test related files can be found under the 'tests' directory. This package comes with C source files and headers, to be used in conjunction with the Python test.

Compiling required C test code and runing the test can be done in a single line, like so (in this example we're at the root directory of the C2Py repository).

cd C2Py/tests/ && make && ./generateTestData.exe && cd ../../ && python3 -c 'import C2Py.tests.test as test; test.run_test()'

To compile and receive the relevant files:

  1. Run a 'make' command when in the 'tests' directory (this requires having a compiler like gcc installed).

IMPORTANT NOTE Please use make sure to compile with the appropriate gcc version (32 or 64 bit) that suits your installed Python executable version. Otherwise some variable types may be in different sizes and the memory dump may not be read correctly.

After compiling you should see three files have been generated: Source.i, SecondFile.i, generateTestData.exe.

  1. Run the executable to generate a binary file which the test will read. Should be named 'output'.

  2. In Python console, run the following:

    import C2Py.tests.test as test
    test.run_test()

    Expect test output to the console. All tests should pass.

This package has been tested with gcc 4.9.2, Python 3.8.5

Not Supported (nor will be)

Some potential features will unfortunately NOT be supported by this package:

  • Generating an array of structs\unions. The convert method's first parameter will receive ONLY a struct declaration name or typedef name. to generate an array of structs while populating them from a binary file, for example, simply use a loop and the 'offset' parameter in 'convert()' to access the correct memory section in the file.
  • char arrays (or strings). All chars shall be treated as bytes. Bytes with a value representing a readable ASCII character (currently set between the range of 32 to 126) shall be displayed as a character. All other values shall be displayed as integer in hex representation. All byte arrays shall be shown in a list form, never a string.

Contributors

Sagie Levy

License

Copyright (C) 2015 Tandem Group Software

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

c2py's People

Contributors

dragorn421 avatar sagielevy avatar sagielightricks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

c2py's Issues

Deeply recursive struct declaration is not supported

The current implementation of the engine cannot parse recursively declared structs (only a 2 level declaration is supported, e.g.)

struct Test8
{
  struct Test7
  {
    int a;
  };

  struct Test7 b;
};

but the following will fail:

struct Test1
{
  struct Test2
  {
    int a;

    struct Test3
    {
      int b;
    };
  };

  struct Test2 c;
};

Fixing this requires using an abstract syntax tree (or some other tree or stack based implementation) for the parsing engine instead of just regexes.

DefaultBinaryFileC2PyHandler returns weird values

This is my test.c file:

void main() {
	struct my_struct {
	  int a;
	  char b;
	  int c;
	  float d;
	};
	struct my_struct instance = {0x00, 'o', 0x00, 3.2};
}

And this the script that I am using to run C2Py after compiling:

import C2Py.C2PyHandler as c2p
binary_file_handler = c2p.DefaultBinaryFileC2PyHandler("/home/.../C2Py/test_c.i", "/home/.../C2Py/test_c")  # modify PATH to run
result_struct = binary_file_handler.convert(struct_declaration="my_struct")
print(result_struct)

And this is the output I am getting:

my_struct {
	a: 0x464c457f
	b: 0x2
	c: 0x0
	d: 0.0
}

Is this a bug or am I doing something wrong? Thank you.

Support for `int a, b;`-like-declared fields

Fields declared like int a, b; (same type for the two fields a and b) aren't supported

Workaround:
Add this to the start of C2PyConverter._extract_instance in C2Py/C2PyEngine.py:

        if all(c not in struct_data for c in "()"): # prevent doing weird things in case there may be function pointers, the only other thing to use commas in struct fields afaik but I may be wrong
            assert isinstance(struct_data, str)
            semicolon_splits = struct_data.split(";")
            fields_processed = []
            for field_line in semicolon_splits:
                if field_line.strip() == "":
                    continue
                line_fields = field_line.split(",")
                first_line_field_whitespace_split = line_fields[0].split()
                type_qualifier = " ".join(first_line_field_whitespace_split[:-1])
                fields_processed.append(type_qualifier + " " + first_line_field_whitespace_split[-1])
                fields_processed.extend((type_qualifier + " " + field_name) for field_name in line_fields[1:])
            new_struct_data = "".join((field + ";") for field in fields_processed)
            struct_data = new_struct_data

It will replace constructs like int a, b; with int a;int b; so the loop after works as expected.

Dirty hack imo so I won't PR it, but I didn't feel like messing with the regex or the loop and most likely breaking stuff

Endianness

C2Py uses ctypes.Structure, which defaults to the system's endianness. It would be nice to be able to choose the endianness.

Workaround: ctypes.Structure = ctypes.BigEndianStructure after import ctypes in C2Py/C2PyEngine.py. This probably has desastrous side effects, don't use in a serious application. It seems to work well enough in my use case

Comparing structs or unions

A possible feature for the C2Py package is overriding the eq of the structs/unions to attempt to compare fields. This method's implementation would be most likely similar to that of the currently existing recursive_print() method in C2PyEngine.py module

Struct packing is not supported

The current version of the C2Py package does not support treating certain structs/unions as packed (via attribute packed/aligned/pragma pack). This feature needs to be implemented in 'Parse()' method in C2PyEngine module which the parses the C code. Any successful attempts at making this feature would be very much appreciated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.