SaeLog #8: Aplikowanie zmian do kodu programu

W wolnych chwilach pracowałem nad funkcjonalnością patchowania plików w moim projekcie strzykawki – syringe. Funkcja ta ukazała się pod postacią komendy patch. Nie tylko potrafi ona nakładać IDA-owe pliki diff na standardowe binarki, ale także, co było dla mnie ważne, bezpośrednio na dane zapisane w formacie IntelHex. Takiej możliwości potrzebowałem, aby móc dokończyć całą zabawę z analizatorem logicznym Saleae Logic i finalnie zaaplikować wszystko do programu. A ostatecznie rownież wygenerować łatkę rozwiązującą problem.

Generowanie pliku diff dla firmware

Plik dif wygenerowany przez IDA-e, z modyfikacjami kodu firmware jakie wcześniej dokonałem (SaeLog #6 i SaeLog #7) mogę w łatwy sposób nałożyć na oryginalny kod zapisany w pliku hex. Wystarczy użyć polecenia patch:

syringe patch -f IDA --target "Intel Hex" C:\SaeLog\firmware.hex C:\SaeLog\firmware.dif

Porównując wynikowy plik zawierający zmodyfikowany kod z oryginalnym plikiem hex, przy pomocy jakiegoś rodzaju narzędzia typu diff/merge, będzie możliwe stworzenie typowego diff-a. Taki standardowy plik zmian w bardziej ludzki sposób przedstawi zmiany jakie zaszły w pliku hex, a także będzie służył wielką pomocą przy modyfikacji programu Logic.exe.

Mój diff prezentuje się następująco:

--- C:/SaeLog/firmware_org.hex	Pt 2015-12-11 21:07:56
+++ C:/SaeLog/firmware.hex	Pt 2015-12-11 21:08:22
@@ -323,13 +323,13 @@
 :02159800D3225C
 :02159A00C3226A
 :100D74008F598D5A90E678E0FFEF4480FF90E67833
-:100D8400EFF090E67974A0F090E678E0FFEF30E0C1
-:100D9400F790E678E0FFEF20E11B90E678E0FFEFC4
+:100D8400EFF07400120B300090E678E0FFEF30E0F3
+:100D9400F790E678E0FFEF20E13B90E678E0FFEFA4
 :100DA4004440FF90E678EFF090E678E0FFEF30E61D
 :100DB400C380F580BF90E679E55AF090E678E0FFCD
-:100DC400EF30E0F790E678E0FFEF20E11B90E67863
-:100DD400E0FFEF4440FF90E678EFF090E678E0FF24
-:100DE400EF30E69080F5808C90E679E559F090E656
+:100DC400EF30E0F790E678E0FFEF30E1CDE55A70E0
+:100DD400178D5A80E090E678E030E405AD5A755AF4
+:100DE4000080D29080F5808C90E679E559F090E609
 :100DF40078E0FFEF30E0F790E678E0FFEF20E11FC6
 :100E040090E678E0FFEF4440FF90E678EFF090E65C
 :100E140078E0FFEF20E603020D7880F2020D78906F
@@ -337,15 +337,15 @@
 :0D0E3400E0FFEF30E60680F522020D782287
 :0809FB008F428B438A448945B9
 :100A0300AB43AA44A9458B478A48894990E678E0D5
-:100A1300FFEF4480FF90E678EFF090E67974A0F062
+:100A1300FFEF4480FF90E678EFF07400120B300094
 :100A230090E678E0FFEF30E0F790E678E0FFEF2024
-:100A3300E11B90E678E0FFEF4440FF90E678EFF0AB
+:100A3300E13B90E678E0FFEF4440FF90E678EFF08B
 :100A430090E678E0FFEF30E6C380F580BF90E6796B
 :100A5300E542F090E678E0FFEF30E0F790E678E0EB
-:100A6300FFEF20E11B90E678E0FFEF4440FF90E6C4
-:100A730078EFF090E678E0FFEF30E69080F5808C39
-:100A830090E678E0FFEF4480FF90E678EFF090E6A1
-:100A93007974A1F090E678E0FFEF30E0F790E67824
+:100A6300FFEF30E1CDE542701A8B4280E090E678EB
+:100A7300E030E405AB4275420080D29080F5808C73
+:100A830090E678E0FFEF4480FF90E678EFF07401A2
+:100A9300120B300090E678E0FFEF30E0F790E67855
 :100AA300E0FFEF20E11F90E678E0FFEF4440FF9086
 :100AB300E678EFF090E678E0FFEF20E603020A0F16
 :100AC30080F2020A0F90E679E0FF8F4A90E678E021
@@ -354,9 +354,9 @@
 :100AF30090E678EFF090E679E0FFAB47AA48A94982
 :100B0300EF120FFE74012549F549E43548F5489085
 :100B1300E678E0FFEF30E0F790E678E0FFEF20E1E2
-:100B230028E54614FFEF654A601F90E678E0FFEF83
-:100B33004440FF90E678EFF090E678E0FFEF20E6A0
-:100B430003020A0380F2020A03054A808B90E678C7
+:100B230028E54614FFEF654A601F020A3524A0FF3B
+:100B330090E678E030E404EF2402FFEF90E679F0EA
+:100B430022020A0380F2020A03054A808B90E678A8
 :100B5300E0FFEF4440FF90E678EFF090E678E0FFA7
 :0A0B6300EF30E60680F522020A0FCB
 :010B6D002265

Zmianie uległo tylko (a może aż 14) linii, ale gdy przyjrzymy się bliżej to będzie to tylko 91 bajtów, jakie zawierała oryginalna latka + zaktualizowane checksumy.

Generowanie patcha dla logic.exe

Wiem już które linie w reprezentacji IntelHex firmware ulegają zmianie, więc bez problemu mogę je zlokalizować w sekcji .rdata pliku wykonywalnego aplikacji. Poniżej odpowiednio adres, offset w pliku i zmienione dane, jakie powinny znaleźć się pod podanym adresem:

00CE2518	008E0B18	:100D8400EFF07400120B300090E678E0FFEF30E0F3
00CE24EC	008E0AEC	:100D9400F790E678E0FFEF20E13B90E678E0FFEFA4
00CE2468	008E0A68	:100DC400EF30E0F790E678E0FFEF30E1CDE55A70E0
00CE243C	008E0A3C	:100DD400178D5A80E090E678E030E405AD5A755AF4
00CE2410	008E0A10	:100DE4000080D29080F5808C90E679E559F090E609
00CE22C4	008E08C4	:100A1300FFEF4480FF90E678EFF07400120B300094
00CE226C	008E086C	:100A3300E13B90E678E0FFEF4440FF90E678EFF08B
00CE21E8	008E07E8	:100A6300FFEF30E1CDE542701A8B4280E090E678EB
00CE21BC	008E07BC	:100A7300E030E405AB4275420080D29080F5808C73
00CE2190	008E0790	:100A830090E678E0FFEF4480FF90E678EFF07401A2
00CE2164	008E0764	:100A9300120B300090E678E0FFEF30E0F790E67855
00CE1FD8	008E05D8	:100B230028E54614FFEF654A601F020A3524A0FF3B
00CE1FAC	008E05AC	:100B330090E678E030E404EF2402FFEF90E679F0EA
00CE1F80	008E0580	:100B430022020A0380F2020A03054A808B90E678A8

Takie dane są wystarczające do napisania prostego programu lub skryptu modyfikującego plik aplikacji. A jeśli syringe może aplikować patche z IDA, to najłatwiej byłoby pokusić się jednak o wygenerowanie takowych plików. Mogłoby to ułatwić zastosowanie finalnych modyfikacji zainteresowanym użytkownikom. Ale, że nie bardzo chciało mi się przyklepywać zmodyfikowane dane, to sobie walnąłem prosty skrypt w perlu:

#!/usr/bin/perl
 
use strict;
use warnings;
 
my $source = 'logic.patch';
my $target = 'logic.exe';
 
open SH, '<', $source or die "Open file '$source' failed: $!";
open TH, '+<', $target or die "Open file '$target' failed: $!";
binmode(TH);
 
while (<SH>) {
	my @rec = split(/\t/);
	my $pos = hex($rec[1]);
	chomp ($rec[2]);
	print "Writting data at $pos\n";
	seek TH, $pos, 0 or die "Seek failed: $!";
	print TH $rec[2] or die "Write failed: $!";
}
 
close TH or die "Close file '$target' failed: $!";
close SH or die "Close file '$source' failed: $!";

Teraz wystarczy odpalić skrypt, aby zmiany zostały wprowadzone w pliku programu. Można pokusić się o wpakowanie jako tablicy zawartości pliku logic.patch do skryptu, wtedy cały skrypt można traktować jako typowy patch.

Należy mieć na uwadze, że wszystkie zmiany jakie dokonywałem dotyczą wersji firmware z jaką moje urządzenie wchodziło w interakcje. Aplikacja ma zaszyte kilka wersji firmware, w którejś z części (chyba przy ekstrakcji kodu firmware z aplikacji) o tym pisałem.

Dzięki temu, że starałem się nie zwiększać kodu firmware, ale modyfikować tylko istniejący kod i upychać nowe instrukcje, aplikowanie do programu jest proste. Gdybym zwiększył kod urządzenia, wtedy sprawa byłaby trochę bardziej skomplikowana. Musiałbym gdzieś upchać nowe linie/dane kodu w IntelHex, np. w wolnych przestrzeniach, modyfikować funkcje związane z ładowaniem danych z .rdata do pamięci i inne… mówiąc prosto, dużo więcej zabawy.

Zpatchowany program powinien działać bez zarzutu ;)

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *