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

Support for extracting certificates from digitally signed binaries #42

Merged
merged 28 commits into from
Jan 22, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7bbfdf0
small fix to is_pe so that it will work after seeking elsewhere in th…
Nov 8, 2012
46a8153
libpe: Fix possible memory leaks.
jweyrich Nov 8, 2012
bbe12bd
libpe: Introduce new function pe_get_data_directory.
jweyrich Nov 8, 2012
fcfe946
libpe: Add very basic support for the security directory.
jweyrich Nov 8, 2012
f8ace9e
libpe: Fix indentation and line-breaks.
jweyrich Nov 8, 2012
8f185fe
libpe: Fix missing cert types.
jweyrich Nov 9, 2012
7f270cf
Merge pull request #40 from logan-m-lamb/is_peFix
merces Nov 9, 2012
1d0ae4b
libpe: Ops, fix off-by-1 error.
jweyrich Nov 9, 2012
f54eb30
do not exit readpe if export directory is not found
merces Nov 14, 2012
a001008
Merge branch 'master' of https://github.com/merces/pev into win_certi…
jweyrich Nov 19, 2012
e9accc4
README now contains instructions on how to build in Mac OS X.
jweyrich Dec 29, 2012
8fa06d3
Parse certificates from digitally signed PE's.
jweyrich Dec 29, 2012
1d00753
Fix sign conversion warning.
jweyrich Dec 29, 2012
878d90b
Fix missing static specifier for a couple of functions.
jweyrich Dec 30, 2012
6005050
pesec: Support new CLI parameters --certoutform and --certout.
jweyrich Dec 31, 2012
5decd89
Cosmetic change. Fix style of pointer return and arguments.
jweyrich Dec 31, 2012
70c5021
Fix missing static specifiers.
jweyrich Dec 31, 2012
94e73b7
Remove unused code.
jweyrich Dec 31, 2012
b68490e
Remove more unused code.
jweyrich Dec 31, 2012
6703266
pesec: Only print certificates when --certout is informed.
jweyrich Jan 2, 2013
8a2a85f
pesec: Show all signers and whether certificate signature is valid.
jweyrich Jan 2, 2013
9158bf6
Remove and ignore src/output.
jweyrich Jan 10, 2013
71014bf
Quoting pecoff_v8.docx: "Entries in the section table are numbered st…
jweyrich Jan 10, 2013
faddf52
Merge pull request #41 from marcelomf/master
merces Jan 21, 2013
e58ee84
Add rule to compile peres.
jweyrich Jan 22, 2013
fbe4561
peres: Fix warnings.
jweyrich Jan 22, 2013
a294452
Merge branch 'master' into merge_peres_pesec
jweyrich Jan 22, 2013
5d0fa30
peres: Add constness to string literal.
jweyrich Jan 22, 2013
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ Debug
*.dylib
*.dll
*.o
*.dSYM
*.log
.settings
src/ofs2rva
src/output
src/pedis
src/pehash
src/pepack
Expand Down
59 changes: 59 additions & 0 deletions lib/libpe/dir_entry_security.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#ifndef LIBPE_DIR_ENTRY_SECURITY_H
#define LIBPE_DIR_ENTRY_SECURITY_H

#include "types.h"

#define ANYSIZE_ARRAY 1

// #define WIN_TRUST_MAJOR_REVISION_MASK 0xFFFF0000
// #define WIN_TRUST_MINOR_REVISION_MASK 0x0000FFFF
// #define WIN_TRUST_REVISION_1_0 0x00010000

typedef enum {
// Version 1, legacy version of the Win_Certificate
// structure. It is supported only for purposes of
// verifying legacy Authenticode signatures
WIN_CERT_REVISION_1_0 = 0x0100,
// Version 2 is the current version of the Win_Certificate structure.
WIN_CERT_REVISION_2_0 = 0x0200
} CertRevision;

typedef enum {
WIN_CERT_TYPE_X509 = 0x0001, // bCertificate contains an X.509 (Certificate)
WIN_CERT_TYPE_PKCS_SIGNED_DATA = 0x0002, // bCertificate contains a PKCS#7 (SignedData structure)
WIN_CERT_TYPE_RESERVED_1 = 0x0003, // Reserved
WIN_CERT_TYPE_TS_STACK_SIGNED = 0x0004, // Terminal Server Protocol Stack (Certificate signing)
WIN_CERT_TYPE_EFI_PKCS115 = 0x0EF0,
WIN_CERT_TYPE_EFI_GUID = 0x0EF1
} CertType;

#pragma pack(4)

// Originally declared in Wintrust.h
typedef struct {
// Specified the size, in bytes, of the WIN_CERTIFICATE structure,
// including the data in bCertificate.
DWORD dwLength;
// Indicates the revision of the structure.
WORD wRevision;
// Specifies the type of certificate.
// This member can be one of the following values:
// Value Meaning
// ----------------------------------------------------------------------------------------
// WIN_CERT_TYPE_X509 The certificate contains an X.509 Certificate.
// WIN_CERT_TYPE_PKCS_SIGNED_DATA The certificate contains a PKCS SignedData structure.
// WIN_CERT_TYPE_RESERVED_1 Reserved.
// WIN_CERT_TYPE_TS_STACK_SIGNED
WORD wCertificateType;
// A variable-sized array of bytes that contains the certificate data.
BYTE bCertificate[ANYSIZE_ARRAY];
} WIN_CERTIFICATE;

typedef struct {
DWORD cbData;
BYTE *pbData;
} CRYPT_DATA_BLOB;

#pragma pack()

#endif
73 changes: 48 additions & 25 deletions lib/libpe/pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void *xmalloc(size_t size)

return new_mem;
}

// return a rva of given offset
DWORD ofs2rva(PE_FILE *pe, DWORD ofs)
{
Expand All @@ -48,7 +48,7 @@ DWORD ofs2rva(PE_FILE *pe, DWORD ofs)
ofs < (pe->sections_ptr[i]->PointerToRawData + pe->sections_ptr[i]->SizeOfRawData))
return ofs + pe->sections_ptr[i]->VirtualAddress;
}
return 0;
return 0;
}

QWORD rva2ofs(PE_FILE *pe, QWORD rva)
Expand All @@ -57,7 +57,7 @@ QWORD rva2ofs(PE_FILE *pe, QWORD rva)
return 0;

for (unsigned int i=0; i < pe->num_sections; i++)
{
{
if (rva >= pe->sections_ptr[i]->VirtualAddress &&
rva < (pe->sections_ptr[i]->VirtualAddress + pe->sections_ptr[i]->SizeOfRawData))
return rva - pe->sections_ptr[i]->VirtualAddress + pe->sections_ptr[i]->PointerToRawData;
Expand Down Expand Up @@ -107,7 +107,7 @@ IMAGE_SECTION_HEADER* pe_get_section(PE_FILE *pe, const char *section_name)

if (!pe->num_sections || pe->num_sections > MAX_SECTIONS)
return NULL;

for (unsigned int i=0; i < pe->num_sections; i++)
{
if (memcmp(pe->sections_ptr[i]->Name, section_name, strlen(section_name)) == 0)
Expand All @@ -122,10 +122,10 @@ bool pe_get_resource_entries(PE_FILE *pe)

if (!pe)
return false;

if (pe->rsrc_entries_ptr)
return pe->rsrc_entries_ptr;

if (!pe_get_resource_directory(pe, &dir))
return false;

Expand All @@ -135,11 +135,11 @@ bool pe_get_resource_entries(PE_FILE *pe)
return false;

pe->rsrc_entries_ptr = xmalloc(sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * pe->num_rsrc_entries);

for (unsigned int i=0; i < pe->num_rsrc_entries; i++)
{
pe->rsrc_entries_ptr[i] = xmalloc(sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));

if (!fread(pe->rsrc_entries_ptr[i], sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY), 1, pe->handle))
return false;
}
Expand All @@ -155,9 +155,13 @@ bool pe_get_resource_directory(PE_FILE *pe, IMAGE_RESOURCE_DIRECTORY *dir)
if (!pe_get_directories(pe))
return false;

if (pe->directories_ptr[IMAGE_DIRECTORY_ENTRY_RESOURCE]->Size > 0)
IMAGE_DATA_DIRECTORY *directory = pe_get_data_directory(pe, IMAGE_DIRECTORY_ENTRY_RESOURCE);
if (!directory)
return false;

if (directory->Size > 0)
{
pe->addr_rsrc_dir = rva2ofs(pe, pe->directories_ptr[IMAGE_DIRECTORY_ENTRY_RESOURCE]->VirtualAddress);
pe->addr_rsrc_dir = rva2ofs(pe, directory->VirtualAddress);
if (fseek(pe->handle, pe->addr_rsrc_dir, SEEK_SET))
return false;

Expand All @@ -169,6 +173,15 @@ bool pe_get_resource_directory(PE_FILE *pe, IMAGE_RESOURCE_DIRECTORY *dir)
return false;
}

IMAGE_DATA_DIRECTORY *pe_get_data_directory(PE_FILE *pe, ImageDirectoryEntry entry)
{
if (!pe || !pe->directories_ptr || entry > (WORD)(pe->num_directories - 1))
return NULL;

return pe->directories_ptr[entry];
}


bool pe_get_sections(PE_FILE *pe)
{
IMAGE_SECTION_HEADER **sections;
Expand Down Expand Up @@ -210,8 +223,6 @@ bool pe_get_sections(PE_FILE *pe)

bool pe_get_directories(PE_FILE *pe)
{
IMAGE_DATA_DIRECTORY **dirs;

if (!pe)
return false;

Expand All @@ -230,19 +241,27 @@ bool pe_get_directories(PE_FILE *pe)
if (pe->num_directories > 32)
return false;

dirs = xmalloc(sizeof(IMAGE_DATA_DIRECTORY *) * pe->num_directories);
const size_t directories_size = sizeof(IMAGE_DATA_DIRECTORY *) * pe->num_directories;

pe->directories_ptr = xmalloc(directories_size);
if (!pe->directories_ptr)
return false;

// Zero out the entire block, otherwise if one allocation fails for dirs[i],
// pe_deinit() will try to free wild pointers. This of course does not take
// into consideration that an allocation failure will make the process die.
memset(pe->directories_ptr, 0, directories_size);

for (unsigned int i=0; i < pe->num_directories; i++)
{
dirs[i] = xmalloc(sizeof(IMAGE_DATA_DIRECTORY));
if (!fread(dirs[i], sizeof(IMAGE_DATA_DIRECTORY), 1, pe->handle))
pe->directories_ptr[i] = xmalloc(sizeof(IMAGE_DATA_DIRECTORY));
if (!fread(pe->directories_ptr[i], sizeof(IMAGE_DATA_DIRECTORY), 1, pe->handle))
return false;
}

pe->addr_sections = ftell(pe->handle);
pe->directories_ptr = dirs;

if (!pe->addr_sections || !pe->directories_ptr)
if (!pe->addr_sections)
return false;

return true;
Expand All @@ -269,7 +288,11 @@ bool pe_get_optional(PE_FILE *pe)
if (fseek(pe->handle, pe->addr_optional, SEEK_SET))
return false;

header = xmalloc(sizeof(IMAGE_OPTIONAL_HEADER));
pe->optional_ptr = xmalloc(sizeof(IMAGE_OPTIONAL_HEADER));
if (!pe->optional_ptr)
return false;

header = pe->optional_ptr;

switch (pe->architecture)
{
Expand Down Expand Up @@ -298,10 +321,9 @@ bool pe_get_optional(PE_FILE *pe)
return false;
}

pe->optional_ptr = header;
pe->addr_directories = ftell(pe->handle);

if (!pe->optional_ptr || !pe->addr_directories)
if (!pe->addr_directories)
return false;

return true;
Expand Down Expand Up @@ -346,7 +368,7 @@ bool pe_get_dos(PE_FILE *pe, IMAGE_DOS_HEADER *header)
{
if (!pe)
return false;

if (!pe->handle)
return false;

Expand All @@ -364,10 +386,10 @@ QWORD pe_get_size(PE_FILE *pe)
{
if (pe->size)
return pe->size;

if (fseek(pe->handle, 0, SEEK_END))
return 0;

pe->size = ftell(pe->handle);
rewind(pe->handle);
return pe->size;
Expand All @@ -384,6 +406,7 @@ bool is_pe(PE_FILE *pe)
if (pe->handle == NULL)
return false;

rewind(pe->handle);
if (!fread(&header, sizeof(WORD), 1, pe->handle))
return false;

Expand All @@ -405,9 +428,9 @@ bool is_pe(PE_FILE *pe)
return false;

if (pesig != 0x4550) // "PE\0\0"
return false;
return false;

rewind(pe->handle);
rewind(pe->handle);
return true;
}

Expand Down
Loading