Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Certificate Table parsing and Authentihash support for PE #15987

Merged
merged 1 commit into from
Feb 20, 2020

Conversation

abcSup
Copy link
Contributor

@abcSup abcSup commented Feb 17, 2020

Your checklist for this pull request

  • I've read the guidelines for contributing to this repository
  • I made sure to follow the project's coding style
  • I've added tests that prove my fix is effective or that my feature works (if possible)
  • I've updated the documentation and the radare2 book with the relevant information (if needed)

Detailed description
Add Authentihash and Authentihash check support for Portable Executable. Currently, the Authentihash information are stored in the pe sdb.

Missing steps

  • A signed binary with valid Authentihash to test true case. There seems to be only signature.exe in testbins which has an invalid Authentihash.
  • Include Authentihash in it output (?)

Imo, Authentihash information should be displayed at somewhere specific to the file format. For now, it seems to generate general hashes (md5, sha1, sha256). Adding Authentihash into the command will complicate the code (checking if rclass == pe, get authentihash with sdb_querys, output directly) while the existing code is using a RList of RBinHash, which makes me wonder if there is a cleaner way to do this. For Authentihash check, I thought about adding it into RBinInfo, but that makes the structure less general, so I am looking forward to some feedbacks.

Closing issues
#921

@github-actions github-actions bot added API New API requests, changes, removal RBin labels Feb 17, 2020
@XVilka XVilka added the PE Portable Executable file format handling label Feb 17, 2020
@XVilka XVilka added this to the 4.3.0 milestone Feb 17, 2020
libr/bin/format/pe/pe.c Outdated Show resolved Hide resolved
libr/bin/format/pe/pe.c Outdated Show resolved Hide resolved
libr/bin/format/pe/pe.c Outdated Show resolved Hide resolved
libr/bin/format/pe/pe.c Outdated Show resolved Hide resolved
libr/bin/format/pe/pe.c Outdated Show resolved Hide resolved
libr/bin/format/pe/pe.c Outdated Show resolved Hide resolved
Copy link
Collaborator

@radare radare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor improvements. and ready to merge

@radare radare requested a review from ret2libc February 17, 2020 16:03
@ret2libc
Copy link
Contributor

Missing steps

* [ ]  A signed binary with valid Authentihash to test true case. There seems to be only `signature.exe` in testbins which has an invalid Authentihash.

I do not use Windows. Do you have any of those binary on your system? If so, you can upload it to https://github.com/radareorg/radare2-testbins .

* [ ]  Include Authentihash in `it` output (?)

Imo, Authentihash information should be displayed at somewhere specific to the file format. For now, it seems to generate general hashes (md5, sha1, sha256). Adding Authentihash into the command will complicate the code (checking if rclass == pe, get authentihash with sdb_querys, output directly) while the existing code is using a RList of RBinHash, which makes me wonder if there is a cleaner way to do this. For Authentihash check, I thought about adding it into RBinInfo, but that makes the structure less general, so I am looking forward to some feedbacks.

Maybe you can fix a bit the code around the RBinPlugin->info method. In bin_pe.inc:info() you could compute the authentihash, create a RBinHash structure and put it in info->file_hashes (you should adapt a bit the code in bfile.c:r_bin_file_hash() to consider the case when info->file_hashes is already initialized, or maybe you should always initialize info->file_hashes somewhere else). By doing so the hash will be shown in it and any file format can easily add its own specific hash.

@abcSup
Copy link
Contributor Author

abcSup commented Feb 17, 2020

I do not use Windows. Do you have any of those binary on your system? If so, you can upload it to https://github.com/radareorg/radare2-testbins .

Currently, I am testing it on commercial programs. I will look it up how to sign one without a proper cert.

Maybe you can fix a bit the code around the RBinPlugin->info method. In bin_pe.inc:info() you could compute the authentihash, create a RBinHash structure and put it in info->file_hashes (you should adapt a bit the code in bfile.c:r_bin_file_hash() to consider the case when info->file_hashes is already initialized, or maybe you should always initialize info->file_hashes somewhere else). By doing so the hash will be shown in it and any file format can easily add its own specific hash.

Thanks for the green light, I will proceed to refactor bfile.c:r_bin_file_hash() to make it more general.

@radare
Copy link
Collaborator

radare commented Feb 18, 2020

thanks! i think we are good to remove the WIP after you do this refactor so we will be ready to merge

@XVilka
Copy link
Contributor

XVilka commented Feb 20, 2020

Binary was merged, please update the PR and we are good to go.

* Add Certificate Table parser to PE plugin
* Add SpcIndirectDataContent ASN.1 structure parser
* Add Authentihash calculation and check
* Refactor r_bin_file_hash
* Add tests for Authentihash check
@github-actions github-actions bot added command New commands requests, behaviour changes, removal radare2 labels Feb 20, 2020
@abcSup abcSup changed the title WIP: Add Certificate Table parsing and Authentihash support for PE Add Certificate Table parsing and Authentihash support for PE Feb 20, 2020
@abcSup
Copy link
Contributor Author

abcSup commented Feb 20, 2020

Appveyor and one of the Travis tests passed, but others failed because of:

v/v install radare.r2
Skipping module "radare.r2", since it is missing name or url information.
Makefile:19: recipe for target 'v/v' failed
make[1]: Leaving directory '/home/travis/build/radareorg/radare2/test/src'
make[1]: *** [v/v] Error 1
make[1]: Target 'all' not remade because of errors.
make: *** [src/r2r] Error 2
Makefile:14: recipe for target 'src/r2r' failed
make: Target 'all' not remade because of errors.
+ exit 1

I assume that if we rebuild the tests, it should be fine.

@ret2libc ret2libc self-assigned this Feb 20, 2020
Copy link
Contributor

@ret2libc ret2libc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at it now, I'm not sure adding the securihash to the info method was the best approach :(

I have not run your branch, but I believe r_file_bin_hash will not compute the format-specific hashes, so SecuriHash will be computed only the first time and it will never be updated, right? Also, I think the API is not very good, as it forces users of r_bin_file_hash to save the result in o->info->file_hashes and that's error prone (because you have to remember to manually update that value every time you use r_bin_file_hash) and not very encapsulating.

For the r_bin_file_hash APIs, what about:

// compute hashes of the current rbinfile and return them
RList *r_bin_file_compute_hashes(RBin *bin, int limit);
// set `hashes` as the last computed hashes for the current rbinfile. `hashes` becomes owned by the current rbinfile, so you don't need to free it. If other hashes were previously set for the current rbinfile, they are returned and they should be freed by the caller when not needed anymore.
RList *r_bin_file_set_hashes(RBin *bin, RList *hashes);

So for it you can do something like:

RList *new_hashes = r_bin_file_compute_hashes (bin, limit);
RList *old_hashes = r_bin_file_set_hashes (bin, new_hashes);
.... do the diff, print, etc ....
r_list_free (old_hashes);

And in radare2.c something like:

r_bin_file_set_hashes (bin, r_bin_file_compute_hashes (bin, limit));

With regard to where to place the new securihash, maybe the best thing was indeed to add a RBinPlugin.hashes method and call it at the end of r_bin_file_compute_hashes function.

What do you think?

libr/main/radare2.c Show resolved Hide resolved
if (!info) {
eprintf ("r_bin_get_info: Cannot get bin info");
r_list_free (old_file_hashes);
RList *new_file_hashes = r_bin_file_hash (core->bin, limit);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this does not re-compute the securihash, does it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, it does not.

@abcSup
Copy link
Contributor Author

abcSup commented Feb 20, 2020

Looking at it now, I'm not sure adding the securihash to the info method was the best approach :(

I have not run your branch, but I believe r_file_bin_hash will not compute the format-specific hashes, so SecuriHash will be computed only the first time and it will never be updated, right? Also, I think the API is not very good, as it forces users of r_bin_file_hash to save the result in o->info->file_hashes and that's error prone (because you have to remember to manually update that value every time you use r_bin_file_hash) and not very encapsulating.

For the r_bin_file_hash APIs, what about:

// compute hashes of the current rbinfile and return them
RList *r_bin_file_compute_hashes(RBin *bin, int limit);
// set `hashes` as the last computed hashes for the current rbinfile. `hashes` becomes owned by the current rbinfile, so you don't need to free it. If other hashes were previously set for the current rbinfile, they are returned and they should be freed by the caller when not needed anymore.
RList *r_bin_file_set_hashes(RBin *bin, RList *hashes);

So for it you can do something like:

RList *new_hashes = r_bin_file_compute_hashes (bin, limit);
RList *old_hashes = r_bin_file_set_hashes (bin, new_hashes);
.... do the diff, print, etc ....
r_list_free (old_hashes);

And in radare2.c something like:

r_bin_file_set_hashes (bin, r_bin_file_compute_hashes (bin, limit));

With regard to where to place the new securihash, maybe the best thing was indeed to add a RBinPlugin.hashes method and call it at the end of r_bin_file_compute_hashes function.

What do you think?

Initially, I was thinking that RBinInfo should always keep the original hashes in info->file_hashes and subsequent calls to r_bin_file_hashes will compute new hashes, so the users can always know that the file has been changed previously instead of discarding the old hashes and replacing it with the new ones. And bfile.c:r_bin_file_hashes will not hash files larger than the limit argument and discard the old hashes in info->file_hashes (Authentihash), so keeping the original hashes will be more appropriate.

I think your suggestions are good by including the binary specific hash in RBinInfo as a method and call it from r_bin_compute_hash and having a new method r_bin_file_set_hashes to set and return the old hashes. These help resolving previous design problems I faced.

@ret2libc
Copy link
Contributor

I think your suggestions are good by including the binary specific hash in RBinInfo as a method and call it from r_bin_compute_hash and having a new method r_bin_file_set_hashes to set and return the old hashes. These help resolving previous design problems I faced.

I guess you meant RBinPlugin, right?

@abcSup
Copy link
Contributor Author

abcSup commented Feb 20, 2020

I guess you meant RBinPlugin, right?

Yeah, sorry for the typo. I will work on it first and see how it goes. Thanks for the help! :)

@ret2libc
Copy link
Contributor

No problem, thank you for working on this! The base stuff that calculates the securihash is actually good already I think, it's just a matter of integrating it with r2 code base ;)

@radare radare merged commit 2c6fc43 into radareorg:master Feb 20, 2020
abcSup added a commit to abcSup/radare2 that referenced this pull request Feb 20, 2020
@abcSup
Copy link
Contributor Author

abcSup commented Feb 20, 2020

I have clicked wrong for the revert pull request. I guess I will create another pull request for the refactor in two hours.

@abcSup abcSup mentioned this pull request Feb 20, 2020
4 tasks
@radare
Copy link
Collaborator

radare commented Feb 20, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API New API requests, changes, removal command New commands requests, behaviour changes, removal PE Portable Executable file format handling radare2 RBin
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants