#!/usr/bin/perl
# $Id: insert_hook,v 1.0 92/07/31 17:39:34 cap Exp $
# This program overwrites a few bytes of an executable program with a jump
# instruction to move control to another address. Arguments are:
#
#     insert_hook [-v] <-jmp or -bsr> program from to
#
# where from is the memory address where the jump instruction should be
# inserted, and to is the memory address where the jump should transfer
# control.
#
$usagestring = "usage: insert_hook [-v] <-jmp or -bsr> program from to\n";

require 'newgetopt.pl';
require 'mach-o.pl';

do NGetOpt("v", "jmp", "bsr");

if ($#ARGV != 2) {
    die $usagestring;
} elsif (!$opt_jmp && !$opt_bsr) {
    print STDERR "You must specify an instruction, either -jmp or -bsr.\n";
    die $usagestring;
} elsif ($opt_jmp && $opt_bsr) {
    print STDERR "You must specify only one of -jmp and -bsr.\n";
    die $usagestring;
} else {
    $program = $ARGV[0];
    $from = $ARGV[1];
    $to = $ARGV[2];
    # in case user gave us octal or hex, convert
    $from = oct($from) if ($from =~ /^0/);
    $to = oct($to) if ($to =~ /^0/);
}

open(PROGRAM, "+<$program") || die "Can't open input $ARGV[0]\n";

# get information about this section of the program
($sectname, $segname, $base, $size, $offset) = 
    &section_info(PROGRAM, "__text", "__TEXT");
if ($sectname ne "__text") {	# 
    die "Can't find section __TEXT.__text in $program\n";
}
if ($opt_v) {
    printf "section = $sectname\n";
    printf "segment = $segname\n";
    printf "base    = 0x%x\n", $base;
    printf "size    = 0x%x\n", $size;
    printf "offset  = 0x%x\n", $offset;
}

# code indicating a jump
if ($opt_jmp) {			# absolute jump
    $jmpcode = 0x4ef9;
} elsif ($opt_bsr) {		# forward bsr
    $jmpcode = 0x61ff;
    $to = $to - $from - 2;
}
# seek to the right spot and write the instruction
$seekloc = $from - $base + $offset;
$buf = pack("SL", $jmpcode, $to);
printf "Seeking to %d\n", $seekloc;
seek(PROGRAM, $seekloc, 0);
printf "Writing value 0x%x%08x\n", $jmpcode, $to;
print PROGRAM $buf;

close(PROGRAM);
