line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/usr/bin/perl |
2
|
|
|
|
|
|
|
# vim: set sw=2 expandtab : # |
3
|
|
|
|
|
|
|
# Master version is at https://developer.berlios.de/projects/games-hack/ |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Games::Hack::Patch::x86_64; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
$VERSION=0.13; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
require Exporter; |
10
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
11
|
|
|
|
|
|
|
@EXPORT = qw(GetNOP); |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub GetNOP |
16
|
|
|
|
|
|
|
{ |
17
|
8
|
|
|
8
|
1
|
2719
|
my($adr_start, $adr_end, $disass)=@_; |
18
|
8
|
|
|
|
|
12
|
my($binary, $diff); |
19
|
|
|
|
|
|
|
|
20
|
8
|
|
|
|
|
21
|
$binary=""; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
### Floating point store? Stores always %ST(0). |
23
|
8
|
100
|
|
|
|
57
|
if ($disass =~ m#^f[bi]?st(p)?s? #) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
24
|
|
|
|
|
|
|
{ |
25
|
3
|
100
|
|
|
|
11
|
if ($1) |
26
|
|
|
|
|
|
|
{ |
27
|
|
|
|
|
|
|
# If the "Pop" flag is given in the "fst" ("floating point store") |
28
|
|
|
|
|
|
|
# operation, we need to clean the floating point stack. |
29
|
|
|
|
|
|
|
# We use the "ffreep st(0)" instruction, . |
30
|
2
|
|
|
|
|
4
|
$binary .= "\xdf\xc0"; |
31
|
|
|
|
|
|
|
|
32
|
2
|
|
|
|
|
3
|
$adr_start += 2; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
# Rest gets done by jump. |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
# Popping values from the stack |
37
|
|
|
|
|
|
|
elsif ($disass =~ m#^pop#) |
38
|
|
|
|
|
|
|
{ |
39
|
|
|
|
|
|
|
# increment esp; rest done by jump. |
40
|
|
|
|
|
|
|
# is there a 64bit pop? |
41
|
1
|
|
|
|
|
2
|
$binary .= "\x83\xc4\x04"; |
42
|
1
|
|
|
|
|
1
|
$adr_start += 3; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
### Integer move or direct modification |
45
|
|
|
|
|
|
|
elsif ($disass =~ m#^(mov|or|and|add|sub|xor)#) |
46
|
|
|
|
|
|
|
{ |
47
|
|
|
|
|
|
|
# done by jump. |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
else |
50
|
|
|
|
|
|
|
{ |
51
|
2
|
|
|
|
|
19
|
warn "Unknown instruction '" . $disass . "', patching unsafe!"; |
52
|
2
|
|
|
|
|
10
|
return undef; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
### short jump |
57
|
6
|
100
|
|
|
|
16
|
if (($diff=$adr_end-$adr_start) >= 2) |
58
|
|
|
|
|
|
|
{ |
59
|
|
|
|
|
|
|
# The opcode needs two bytes; these are already consumed, and so the jump |
60
|
|
|
|
|
|
|
# distance has to be reduced. |
61
|
4
|
|
|
|
|
12
|
$binary .= "\xeb" . pack("C", $diff-2); |
62
|
4
|
|
|
|
|
7
|
$adr_end=$adr_start; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
### NOP. |
66
|
|
|
|
|
|
|
# That should never be needed ... all instructions involving memory access |
67
|
|
|
|
|
|
|
# (even via a register) have at least 2 bytes. |
68
|
|
|
|
|
|
|
# (If some value would be persistently stored in a register, we wouldn't |
69
|
|
|
|
|
|
|
# find it by looking at the memory contents.) |
70
|
6
|
100
|
|
|
|
15
|
$binary .= "\x90" x $diff |
71
|
|
|
|
|
|
|
if ($diff=$adr_end-$adr_start) >= 1; |
72
|
|
|
|
|
|
|
|
73
|
6
|
|
|
|
|
17
|
return $binary; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
__END__ |