pmeerw's blog

Sat, 04 May 2019

Rewriting Windows binary with Python's pefile

Using Python module pefile to rewrite a Windows PE/PE+ file (I think both 32-bit and 64-bit are supported, tested 64-bit only). The goal is to append a new section, change the executable's entry point to the new section, jump back to the original entry point (OEP).

#!/usr/env python3

import pefile

def adjust_SectionSize(sz, align):
  if sz % align: sz = ((sz + align) // align) * align
  return sz

pe = pefile.PE('../hello.exe')

last_section = pe.sections[-1]

new_section = pefile.SectionStructure(pe.__IMAGE_SECTION_HEADER_format__)

# fill with zeros
new_section.__unpack__(bytearray(new_section.sizeof()))

# place section header after last section header (assume there is enough room)
new_section.set_file_offset(last_section.get_file_offset() + last_section.sizeof())

new_section.Name = b'.test'
new_section_size = 100

new_section.SizeOfRawData = adjust_SectionSize(new_section_size, pe.OPTIONAL_HEADER.FileAlignment)
new_section.PointerToRawData = len(pe.__data__)

new_section.Misc = new_section.Misc_PhysicalAddress = new_section.Misc_VirtualSize = new_section_size
new_section.VirtualAddress = last_section.VirtualAddress + adjust_SectionSize(last_section.Misc_VirtualSize, pe.OPTIONAL_HEADER.SectionAlignment)

new_section.Characteristics = 0x40000000 | 0x20000000 | 0x20 # read | execute | code

# create new section data containing jump to OEP
reljmp = pe.OPTIONAL_HEADER.AddressOfEntryPoint - (new_section.VirtualAddress + 5)
print('rel jmp %08x' % (reljmp))
new_section_data = bytearray(new_section.SizeOfRawData)
new_section_data[0] = 0xe9
new_section_data[1:4] = reljmp.to_bytes(4, byteorder='little', signed=True)

# change address of entry point to beginning of new section
pe.OPTIONAL_HEADER.AddressOfEntryPoint = new_section.VirtualAddress

# increase size of image
pe.OPTIONAL_HEADER.SizeOfImage += adjust_SectionSize(new_section_size, pe.OPTIONAL_HEADER.SectionAlignment)

# increase number of sections
pe.FILE_HEADER.NumberOfSections += 1

# append new section to structures
pe.sections.append(new_section)
pe.__structures__.append(new_section)

# add new section data to file
pe.__data__ = bytearray(pe.__data__) + new_section_data

pe.write('../hello_patched.exe')

posted at: 10:33 | path: /programming | permanent link

Fri, 03 May 2019

Running x64dbg on Linux (wine)

x64dbg is an open-source x64/x32 for Windows, somewhat following the famous OllyDbg, but a lot more modern. This is based on the latest version of April 30, 2019.

Trying with Ubuntu 18.04 (wine 3.0-1ubuntu1) fails, running winetricks vcrun2013 helps a bit, however, x64dbg then fails when loading an executable (see bug report).

Using the wine-development package provides wine 3.6, and x64dbg works somewhat -- hurray.

posted at: 23:56 | path: /programming | permanent link

Tue, 29 Jan 2019

git am on Windows

Note to self: on Windows use git am --whitespace=nowarn --keep-cr to apply commits previously created by format-patch. WTF?

posted at: 16:32 | path: /programming | permanent link

Mon, 30 Mar 2015

Counting newlines (quickly!)

Here are some thoughts on fefe's counting newlines problem (in German).

Bottom line: SIMD is nifty!

posted at: 14:27 | path: /programming | permanent link

Sun, 26 Jan 2014

Watching for new files on Linux

Linux has a relatively new (2.6.13, June 2005), easy-to-use interface to watch and monitor file operation: inotify. See the Linux Journal article also.

I plan to use it to see when new devices show up under /dev:

#include 

static const char *progname = "ino";

static const char *inotify_mask_str(unsigned mask) {
    switch (mask) {
    case IN_CREATE: return "create";
    case IN_DELETE: return "delete";
    default: return "???";
    }
}

int main() {
    int fd = inotify_init1(0);
    if (fd < 0) {
        fprintf(stderr, "%s: init failed\n", progname);
        exit(EXIT_FAILURE);
    }

    int wd = inotify_add_watch(fd, "/dev", IN_CREATE | IN_DELETE);
    if (wd < 0) {
        fprintf(stderr, "%s: add watch failed\n", progname);
        exit(EXIT_FAILURE);
    }

    while (true) {
       uint8_t buf[sizeof(struct inotify_event) + FILENAME_MAX + 1];
       ssize_t ret = read(fd, &buf, sizeof(buf));
       if (ret < 0) {
           if (errno == EINTR) continue;
           fprintf(stderr, "%s: read failed\n", progname);
           exit(EXIT_FAILURE);
       }
       
       size_t processed = 0;
       while (processed < ret - sizeof(struct inotify_event)) {
           struct inotify_event *iev = (struct inotify_event *) &buf[processed];
           printf("%4zd:%08x %s %s\n", ret,
               iev->mask, inotify_mask_str(iev->mask), iev->name);
           processed += sizeof(struct inotify_event) + iev->len;
       }
   }
   
   close(wd);
   close(fd);
   
   return EXIT_SUCCESS;
}

posted at: 15:31 | path: /programming | permanent link

Made with PyBlosxom