diff options
116 files changed, 27854 insertions, 0 deletions
diff --git a/README.org b/README.org new file mode 100644 index 00000000..53100a0f --- /dev/null +++ b/README.org @@ -0,0 +1,58 @@ +#+LANGUAGE: en +#+OPTIONS: H:3 num:nil toc:nil \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t +#+OPTIONS: TeX:t LaTeX:nil skip:nil d:nil todo:t pri:nil tags:not-in-toc +#+EXPORT_EXCLUDE_TAGS: exclude +#+STARTUP: showall + +* What is Miasm? +Miasm is a a free and open source (GPLv2) reverse engineering framework. + +Miasm aims at analyzing/modifying/generating binary programs. Here is +a non exhausting list of features: + - opening/modifying/generating PE/ELF 32/64 le/be using Elfesteem + - Assembling/Disassembling ia32/ppc/arm + - Representing assembly semantic using intermediate language + - Emulating using jit (dynamic code analysis, unpacking, ...) + - Expression simplification for automatic de-obfuscation + - Graphic disassembler using Grandalf + - ... + +* How does it work? +Miasm embed its own disassembler, intermediate language and +instruction semantic. It is written in Python. + +To emulate code, it uses libtcc to jit C code generate from +intermediate representation. It can emulate shellcodes, parts of +binaries. Python callback can be executed to emulate library +functions. + +* Documentation +Documentation can be found under =doc/=. + +* Obtain Miasm + +* Software requirements +Miasm uses: + +Grandalf (https://github.com/bdcht/grandalf.git) in order to render +graphical disassembler. + +libtcc (http://bellard.org/tcc/) to Jit code for emulation mode. + +python-ply for parsing + +numpy + +* Configuration +Install libtcc +clone grandalf repository +set path: +$ export PYTHONPATH=$PYTHONPATH:path_to_miasm:path_to_elfesteem + +Compile miasm emulation library: +$ cd tools/emul_lib +$ make + +* Misc +Man, does miasm has a link with rr0d? +Yes! crappy code and uggly documentation. diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 00000000..33d125a1 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,126 @@ +## Makefile for LaTeX presentations. +## +## Will compile the LaTeX file as many times as necessary. +## if FAST=1, always compile once +## +## The postscript : +## make mypres.ps +## The PDF, compile only once, even if the TOC or references are outdated +## make mypres.pdf FAST=1 +## The PDF, 4 slides per page, A4 +## make mypres.a4.4.pdf +## The web page (create a directory, needs album: apt-get install album) +## make mypres.www +## +## <phil(at)secdev.org> + +PSNUPOPTS=-W128mm -H96mm -pa4 -m0.5cm -b0.2cm -d +FORMAT ?= 1 + +XFIG_FIGS=$(patsubst %.fig,%.eps,$(wildcard fig/*.fig)) +DIA_FIGS=$(patsubst %.dia,%.eps,$(wildcard fig/*.dia)) +ALL_FIGS=$(XFIG_FIGS) $(DIA_FIGS) + +all: + @echo 'USAGE: make <filename.ext> [FAST=1]' + @echo 'possible extentions :' + @echo ' .dvi, .ps or .pdf' + @echo ' .www to create a directory with web pages' + @echo ' .a4.n.pdf with n in 1-4,6,8,9,16,32 for n slides per page' + + +.SUFFIXES: .pdf .tex .ps .dvi .www .eps .fig + +# cancel built-in implicit rule tex -> dvi +%.dvi:%.tex + +%.eps: %.fig + fig2dev -L eps $< $@ + +%.eps: %.dia + dia -e $@ $< + +%.pdf: %.ps + ps2pdf $*.ps + +%.ps: %.dvi + dvips -Ppdf $* + +%.dvi: %.tex $(ALL_FIGS) + [ -e $*.aux ] || touch $*.aux + while true; do \ + cp $*.aux $*.aux2 ;\ + echo $(FORMAT) | latex $* || { rm $*.aux2 ; break; }; \ + cmp $*.aux $*.aux2 && break ;\ + [ -z "$(FAST)" ] || break ;\ + done + @# if .aux2 does not exist, there was an error. Next line will be false. + @[ -e $*.aux2 ] && rm $*.aux2 + @echo "#######[ warnings ]#######" + @grep -i warning $*.log + @echo "##########################" + + +%.a4.0.ps: %.dvi + dvips -Ppdf -ta4 $* -o $@ + +%.a4.1.ps: %.a4.0.ps + psnup $(PSNUPOPTS) -1 $< $@ + +%.a4.2.ps: %.a4.0.ps + psnup $(PSNUPOPTS) -2 $< $@ + +%.a4.3.ps: %.a4.0.ps + psnup $(PSNUPOPTS) -3 $< $@ + +%.a4.4.ps: %.a4.0.ps + psnup $(PSNUPOPTS) -4 $< $@ + +%.a4.6.ps: %.a4.0.ps + psnup $(PSNUPOPTS) -6 $< $@ + +%.a4.8.ps: %.a4.0.ps + psnup $(PSNUPOPTS) -8 $< $@ + +%.a4.9.ps: %.a4.0.ps + psnup $(PSNUPOPTS) -9 $< $@ + +%.a4.16.ps: %.a4.0.ps + psnup $(PSNUPOPTS) -16 $< $@ + +%.a4.24.ps: %.a4.0.ps + psnup $(PSNUPOPTS) -24 $< $@ + +%.a4.32.ps: %.a4.0.ps + psnup $(PSNUPOPTS) -32 $< $@ + +%.a4.ps: %.a4.0.ps + mv $< $@ + +%.jpg: %.ppm + convert $< $@ + +# gs or pdftoppm ? pdftoppm : better fonts, graphics not anti-aliased +#gs -dBATCH -dNOPAUSE -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -sDEVICE=png16m -sOutputFile=$@/$@-%04d.png -r150 $< +%.www: %.pdf + [ -e $@ ] && rm -rf $@ || true + mkdir $@ + pdftoppm $< $@/$@ + $(MAKE) alljpg PPMDIR=$@ + rm $@/*.ppm + cd $@ ; album -geometry 200x150 + +alljpg: + @$(MAKE) $(patsubst %.ppm,%.jpg, $(wildcard $(PPMDIR)/*.ppm)) + + +.PRECIOUS: %.dvi %.ps %.pdf %.eps + +.PHONY: clean,test + +clean: + rm -f *.toc *.aux *.vrb *.snm *.log *.out *.nav *.ps *.dvi + + +overclean: clean + rm -f *.pdf diff --git a/doc/bigcenter.sty b/doc/bigcenter.sty new file mode 100644 index 00000000..536c7bd2 --- /dev/null +++ b/doc/bigcenter.sty @@ -0,0 +1,7 @@ +\newskip\@bigflushglue \@bigflushglue = -100pt plus 1fil + +\def\bigcenter{\trivlist \bigcentering\item\relax} +\def\bigcentering{\let\\\@centercr\rightskip\@bigflushglue% +\leftskip\@bigflushglue +\parindent\z@\parfillskip\z@skip} +\def\endbigcenter{\endtrivlist} diff --git a/doc/figs/calc_mod.eps b/doc/figs/calc_mod.eps new file mode 100644 index 00000000..4f3ddfe1 --- /dev/null +++ b/doc/figs/calc_mod.eps Binary files differdiff --git a/doc/figs/calc_mod.png b/doc/figs/calc_mod.png new file mode 100644 index 00000000..40a09804 --- /dev/null +++ b/doc/figs/calc_mod.png Binary files differdiff --git a/doc/figs/conficker_1.eps b/doc/figs/conficker_1.eps new file mode 100644 index 00000000..e3370063 --- /dev/null +++ b/doc/figs/conficker_1.eps Binary files differdiff --git a/doc/figs/conficker_1.png b/doc/figs/conficker_1.png new file mode 100644 index 00000000..73bb2711 --- /dev/null +++ b/doc/figs/conficker_1.png Binary files differdiff --git a/doc/figs/conficker_2.eps b/doc/figs/conficker_2.eps new file mode 100644 index 00000000..115c00ba --- /dev/null +++ b/doc/figs/conficker_2.eps Binary files differdiff --git a/doc/figs/conficker_2.png b/doc/figs/conficker_2.png new file mode 100644 index 00000000..d5f990e5 --- /dev/null +++ b/doc/figs/conficker_2.png Binary files differdiff --git a/doc/figs/conficker_3.eps b/doc/figs/conficker_3.eps new file mode 100644 index 00000000..a8008da6 --- /dev/null +++ b/doc/figs/conficker_3.eps Binary files differdiff --git a/doc/figs/conficker_3.png b/doc/figs/conficker_3.png new file mode 100644 index 00000000..9d9aded2 --- /dev/null +++ b/doc/figs/conficker_3.png Binary files differdiff --git a/doc/figs/conficker_4.eps b/doc/figs/conficker_4.eps new file mode 100644 index 00000000..d41d2cf5 --- /dev/null +++ b/doc/figs/conficker_4.eps Binary files differdiff --git a/doc/figs/conficker_4.png b/doc/figs/conficker_4.png new file mode 100644 index 00000000..a1fce082 --- /dev/null +++ b/doc/figs/conficker_4.png Binary files differdiff --git a/doc/figs/conficker_5.eps b/doc/figs/conficker_5.eps new file mode 100644 index 00000000..91e3ec0b --- /dev/null +++ b/doc/figs/conficker_5.eps Binary files differdiff --git a/doc/figs/conficker_5.png b/doc/figs/conficker_5.png new file mode 100644 index 00000000..5f572e25 --- /dev/null +++ b/doc/figs/conficker_5.png Binary files differdiff --git a/doc/figs/gandalf_01.eps b/doc/figs/gandalf_01.eps new file mode 100644 index 00000000..a03c2ae1 --- /dev/null +++ b/doc/figs/gandalf_01.eps Binary files differdiff --git a/doc/figs/gandalf_01.png b/doc/figs/gandalf_01.png new file mode 100644 index 00000000..ca7cc215 --- /dev/null +++ b/doc/figs/gandalf_01.png Binary files differdiff --git a/doc/figs/gen_graph.eps b/doc/figs/gen_graph.eps new file mode 100644 index 00000000..fb1de3a7 --- /dev/null +++ b/doc/figs/gen_graph.eps Binary files differdiff --git a/doc/figs/gen_graph.png b/doc/figs/gen_graph.png new file mode 100644 index 00000000..a6dc416b --- /dev/null +++ b/doc/figs/gen_graph.png Binary files differdiff --git a/doc/figs/ircbot_1.eps b/doc/figs/ircbot_1.eps new file mode 100644 index 00000000..9795355d --- /dev/null +++ b/doc/figs/ircbot_1.eps Binary files differdiff --git a/doc/figs/ircbot_1.png b/doc/figs/ircbot_1.png new file mode 100644 index 00000000..9da4d445 --- /dev/null +++ b/doc/figs/ircbot_1.png Binary files differdiff --git a/doc/figs/ircbot_2.eps b/doc/figs/ircbot_2.eps new file mode 100644 index 00000000..a75180c0 --- /dev/null +++ b/doc/figs/ircbot_2.eps Binary files differdiff --git a/doc/figs/ircbot_2.png b/doc/figs/ircbot_2.png new file mode 100644 index 00000000..83de6c06 --- /dev/null +++ b/doc/figs/ircbot_2.png Binary files differdiff --git a/doc/figs/ishield_unpacked.eps b/doc/figs/ishield_unpacked.eps new file mode 100644 index 00000000..b866983b --- /dev/null +++ b/doc/figs/ishield_unpacked.eps Binary files differdiff --git a/doc/figs/ishield_unpacked.png b/doc/figs/ishield_unpacked.png new file mode 100644 index 00000000..0784ff27 --- /dev/null +++ b/doc/figs/ishield_unpacked.png Binary files differdiff --git a/doc/figs/mebroot_0.eps b/doc/figs/mebroot_0.eps new file mode 100644 index 00000000..6ec74639 --- /dev/null +++ b/doc/figs/mebroot_0.eps Binary files differdiff --git a/doc/figs/mebroot_0.png b/doc/figs/mebroot_0.png new file mode 100644 index 00000000..4f29c757 --- /dev/null +++ b/doc/figs/mebroot_0.png Binary files differdiff --git a/doc/figs/mebroot_1.eps b/doc/figs/mebroot_1.eps new file mode 100644 index 00000000..a6980bc6 --- /dev/null +++ b/doc/figs/mebroot_1.eps Binary files differdiff --git a/doc/figs/mebroot_1.png b/doc/figs/mebroot_1.png new file mode 100644 index 00000000..48a8f1b0 --- /dev/null +++ b/doc/figs/mebroot_1.png Binary files differdiff --git a/doc/figs/mebroot_2.eps b/doc/figs/mebroot_2.eps new file mode 100644 index 00000000..181a0a5b --- /dev/null +++ b/doc/figs/mebroot_2.eps Binary files differdiff --git a/doc/figs/mebroot_2.png b/doc/figs/mebroot_2.png new file mode 100644 index 00000000..9fe802a8 --- /dev/null +++ b/doc/figs/mebroot_2.png Binary files differdiff --git a/doc/figs/mebroot_3.eps b/doc/figs/mebroot_3.eps new file mode 100644 index 00000000..754c0af3 --- /dev/null +++ b/doc/figs/mebroot_3.eps Binary files differdiff --git a/doc/figs/mebroot_3.png b/doc/figs/mebroot_3.png new file mode 100644 index 00000000..c663f0ed --- /dev/null +++ b/doc/figs/mebroot_3.png Binary files differdiff --git a/doc/figs/mebroot_4.eps b/doc/figs/mebroot_4.eps new file mode 100644 index 00000000..39d1ab70 --- /dev/null +++ b/doc/figs/mebroot_4.eps Binary files differdiff --git a/doc/figs/mebroot_4.png b/doc/figs/mebroot_4.png new file mode 100644 index 00000000..6b152c06 --- /dev/null +++ b/doc/figs/mebroot_4.png Binary files differdiff --git a/doc/figs/mebroot_5.eps b/doc/figs/mebroot_5.eps new file mode 100644 index 00000000..d268e4fe --- /dev/null +++ b/doc/figs/mebroot_5.eps Binary files differdiff --git a/doc/figs/mebroot_5.png b/doc/figs/mebroot_5.png new file mode 100644 index 00000000..e5f31422 --- /dev/null +++ b/doc/figs/mebroot_5.png Binary files differdiff --git a/doc/figs/mebroot_6.eps b/doc/figs/mebroot_6.eps new file mode 100644 index 00000000..c1abf406 --- /dev/null +++ b/doc/figs/mebroot_6.eps Binary files differdiff --git a/doc/figs/mebroot_6.png b/doc/figs/mebroot_6.png new file mode 100644 index 00000000..734b1df9 --- /dev/null +++ b/doc/figs/mebroot_6.png Binary files differdiff --git a/doc/figs/mebroot_7.eps b/doc/figs/mebroot_7.eps new file mode 100644 index 00000000..49f0d8ac --- /dev/null +++ b/doc/figs/mebroot_7.eps Binary files differdiff --git a/doc/figs/mebroot_7.png b/doc/figs/mebroot_7.png new file mode 100644 index 00000000..80124211 --- /dev/null +++ b/doc/figs/mebroot_7.png Binary files differdiff --git a/doc/figs/mebroot_obf_01.eps b/doc/figs/mebroot_obf_01.eps new file mode 100644 index 00000000..47260ddd --- /dev/null +++ b/doc/figs/mebroot_obf_01.eps @@ -0,0 +1,204 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (mebroot_obf_01.eps) +%%CreationDate: (2010-01-22T11:25:52+01:00) +%%BoundingBox: 0 0 605 613 +%%HiResBoundingBox: 0 0 605 613 +%%LanguageLevel: 2 +%%Pages: 1 +%%EndComments + +%%BeginDefaults +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/DirectClassImage +{ + % + % Display a DirectClass image. + % + colorspace 0 eq + { + /DeviceRGB setcolorspace + << + /ImageType 1 + /Width columns + /Height rows + /BitsPerComponent 8 + /Decode [0 1 0 1 0 1] + /ImageMatrix [columns 0 0 rows neg 0 rows] + compression 0 gt + { /DataSource pixel_stream /RunLengthDecode filter } + { /DataSource pixel_stream /RunLengthDecode filter } ifelse + >> image + } + { + /DeviceCMYK setcolorspace + << + /ImageType 1 + /Width columns + /Height rows + /BitsPerComponent 8 + /Decode [1 0 1 0 1 0 1 0] + /ImageMatrix [columns 0 0 rows neg 0 rows] + compression 0 gt + { /DataSource pixel_stream /RunLengthDecode filter } + { /DataSource pixel_stream /RunLengthDecode filter } ifelse + >> image + } ifelse +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % colors: number of colors in the colormap. + % + currentfile buffer readline pop + token pop /colors exch def pop + colors 0 eq + { + % + % Image is grayscale. + % + currentfile buffer readline pop + token pop /bits exch def pop + /DeviceGray setcolorspace + << + /ImageType 1 + /Width columns + /Height rows + /BitsPerComponent bits + /Decode [0 1] + /ImageMatrix [columns 0 0 rows neg 0 rows] + compression 0 gt + { /DataSource pixel_stream /RunLengthDecode filter } + { + /DataSource pixel_stream /RunLengthDecode filter + << + /K -1 + /Columns columns + /Rows rows + >> /CCITTFaxDecode filter + } ifelse + >> image + } + { + % + % Parameters: + % colormap: red, green, blue color packets. + % + /colormap colors 3 mul string def + currentfile colormap readhexstring pop pop + currentfile buffer readline pop + [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace + << + /ImageType 1 + /Width columns + /Height rows + /BitsPerComponent 8 + /Decode [0 255] + /ImageMatrix [columns 0 0 rows neg 0 rows] + compression 0 gt + { /DataSource pixel_stream /RunLengthDecode filter } + { /DataSource pixel_stream /RunLengthDecode filter } ifelse + >> image + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % colorspace: 0-RGB or 1-CMYK. + % compression: 0-RLECompression or 1-NoCompression. + % hex color packets. + % + gsave + /buffer 512 string def + /pixel_stream currentfile def + + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /colorspace exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 0 605 613 +userdict begin +%%BeginData: 1000988 Binary Bytes +DisplayImage +0 0 +605 613 +12.000000 +605 613 +0 +0 +0 +~ýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿý~þÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþ~ÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿ~ýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿý~þÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþ~ÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿ~ýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿý~þÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþ~ÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿ~ýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿý~þÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþ~ÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿ~ýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿý~þÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþ~ÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿ~ýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿý~þÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþ~ÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿ~ýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿý~þÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþ~ÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿ~ýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿý~þÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþ~ÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿ~ýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿý~þÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþ~ÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿ~ýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿý~þÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿýþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ~üþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿü~þÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþ~ÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿwüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿüþÿ‚ +00ÿ¬¬ÿ77ÿ¸¸²ÿþ +;;ÿNNÿ½½ÿddýÿ llÿIIÿÓÓÿ22ÿ‚‚÷ÿ +44ÿEEÿÎÎÿOOýÿ +BBÿ77ÿ¤¤ÿyy¯ÿþ +¶¶Úyy¼ôôù!!þ ÇÒÒè²²ÙŠŠÄòÿf³‹Å¨ÇãÕ9œj°ØÄjµl¶‘êôïËÿþ +‡Ã˜Ì Çâ +¦¦Òrr¹OO§ŽŽþÇþãñââðøÿY¬Yþÿlµl¼Ý¼¾Þ¾E£EC¡C›ÿþ + +…»»ÝþÿGŽŽÇxx»LL¦nn¶ââð¥¥Òÿþÿ{¾z™Ë™¦Ò¦99r¹r•Ê•«Ô«H¤Fÿýÿ§¥Õùÿó@Ÿ@k¶kq·qVªV§Ó§.˜.òÿ$“$öúö…Â…‚þÿ;:žþÿþ +ˆº°ç3ž/©Õ©¤Ñ¤×ë×/—/€¿€f³f¸Û¸ûÿúüútºt»Ý»…Â…;;×îÔÝÚñqq¸øÿþ + +…ôôúVV«ûÿŽªÿþ +‰»±ç3.¬Ö¬£Ñ£¡Ð¡""¿ Ï õÿb°búüúŠÅŠd²dg¶däÜútt¹øÿþ +ÿÿšÿÿ—ÿÿ‹üÿ-ÿÿ€ÿÿžÿÿ‰ÿÿ*üÿ +õõÿññÿ¾¾ÿââýÿÃÃâÿææ‚ÿûÿþ +‰»±ç3.¬Ö¬£Ñ£¼Þ¼ ÀŠÄŠíöíøÿ„„ãñã3™3ûÿ×Öëtt¹øÿþ +<<``¯¹¹Ü__þ¯ +‚‚ÀÑÑèqq¸††þÃá[[ÌÌåÚÿ¦¦ÓuuºÇ··Û··Ûpp¸||½ŸŸÏààðþÿ——ÊŽŽÆøÿÇ]]®ííöhh³§§Ó‹‹Åss¹õÿ ``¯óóù››Íxx»zz¼¿¿ß½½Þ??Ÿ¹¹Ûßßïkkµþþþ + +…ûûýþ +ßßîdd²ÃÃáuuþº ÜYY¬YY¬§§ÓÝÿýýþii´òòø¤¤Ñkkµååò……Âoo·þÿ +‰»±ç3.¬Ö¬£Ñ£ÏçÏ‚À‚|½|àïàøÿÏçÏq¸qs¹sE¢EÎêËÞÛòtt¹øÿþ +þÿ•Ê•‘È‘ÑèÑòÿ¨¨ÓŠŠÅþÿÂÂà×ÿþ +ˆ»±ç3.©Ô©¤Ñ¤ÕêÕ0—0€¿€f³f¶Ú¶ûÿùüùr¹rÀßÀ[[&“&ðûíÛÙïqq¸øÿþ + +…““Éööûpp¸ÊÊ䎎ǿããñµµÚøÿ””ÊŸŸÏòòøpp¸ÊÊ䦦ÓkkµùùüûÿÐÐç +%%EndData +end +%%PageTrailer +%%Trailer +%%BoundingBox: 0 0 605 613 +%%HiResBoundingBox: 0 0 605 613 +%%EOF diff --git a/doc/figs/mebroot_obf_01.png b/doc/figs/mebroot_obf_01.png new file mode 100644 index 00000000..ac379c9a --- /dev/null +++ b/doc/figs/mebroot_obf_01.png Binary files differdiff --git a/doc/figs/mebroot_obfdel_01.eps b/doc/figs/mebroot_obfdel_01.eps new file mode 100644 index 00000000..33f379b0 --- /dev/null +++ b/doc/figs/mebroot_obfdel_01.eps @@ -0,0 +1,205 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (mebroot_obfdel_01.eps) +%%CreationDate: (2010-01-22T11:26:06+01:00) +%%BoundingBox: 0 0 211 683 +%%HiResBoundingBox: 0 0 211 683 +%%LanguageLevel: 2 +%%Pages: 1 +%%EndComments + +%%BeginDefaults +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/DirectClassImage +{ + % + % Display a DirectClass image. + % + colorspace 0 eq + { + /DeviceRGB setcolorspace + << + /ImageType 1 + /Width columns + /Height rows + /BitsPerComponent 8 + /Decode [0 1 0 1 0 1] + /ImageMatrix [columns 0 0 rows neg 0 rows] + compression 0 gt + { /DataSource pixel_stream /RunLengthDecode filter } + { /DataSource pixel_stream /RunLengthDecode filter } ifelse + >> image + } + { + /DeviceCMYK setcolorspace + << + /ImageType 1 + /Width columns + /Height rows + /BitsPerComponent 8 + /Decode [1 0 1 0 1 0 1 0] + /ImageMatrix [columns 0 0 rows neg 0 rows] + compression 0 gt + { /DataSource pixel_stream /RunLengthDecode filter } + { /DataSource pixel_stream /RunLengthDecode filter } ifelse + >> image + } ifelse +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % colors: number of colors in the colormap. + % + currentfile buffer readline pop + token pop /colors exch def pop + colors 0 eq + { + % + % Image is grayscale. + % + currentfile buffer readline pop + token pop /bits exch def pop + /DeviceGray setcolorspace + << + /ImageType 1 + /Width columns + /Height rows + /BitsPerComponent bits + /Decode [0 1] + /ImageMatrix [columns 0 0 rows neg 0 rows] + compression 0 gt + { /DataSource pixel_stream /RunLengthDecode filter } + { + /DataSource pixel_stream /RunLengthDecode filter + << + /K -1 + /Columns columns + /Rows rows + >> /CCITTFaxDecode filter + } ifelse + >> image + } + { + % + % Parameters: + % colormap: red, green, blue color packets. + % + /colormap colors 3 mul string def + currentfile colormap readhexstring pop pop + currentfile buffer readline pop + [ /Indexed /DeviceRGB colors 1 sub colormap ] setcolorspace + << + /ImageType 1 + /Width columns + /Height rows + /BitsPerComponent 8 + /Decode [0 255] + /ImageMatrix [columns 0 0 rows neg 0 rows] + compression 0 gt + { /DataSource pixel_stream /RunLengthDecode filter } + { /DataSource pixel_stream /RunLengthDecode filter } ifelse + >> image + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % colorspace: 0-RGB or 1-CMYK. + % compression: 0-RLECompression or 1-NoCompression. + % hex color packets. + % + gsave + /buffer 512 string def + /pixel_stream currentfile def + + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /colorspace exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 0 211 683 +userdict begin +%%BeginData: 346429 Binary Bytes +DisplayImage +0 0 +211 683 +12.000000 +211 683 +0 +0 +0 +~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ~þþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþ~þÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþ~ÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿPþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿþþÿ‚ +ššÿWWÿ††ÿ//ýÿîîÿBBÿYYÿ„„ÿeeÿÜÜúÿˆˆÿ¥¥ÿWWÿTTÿ¿¿ÿòòÿAAÿ66ÿOO¬ÿþ + +…ÚÚ씔ʇ‡Ãääñòÿh´Ž1™eþÿ0—cÀßÏ%“\Æ©Èÿþ + +…þÿ +… +ÉãÉõÿ_°_õùõ!!M¦Mþÿ??ŸïÿJJ¤¥¥Ñ}}½ììõÍÍæ‚þÿþ +<<``¯¹¹Ü__þ¯ +‰»±ç3.¬Ö¬£Ñ£ÏçÏ‚À‚|½|àïàøÿÏçÏq¸qs¹sE¢EÎêËÞÛòtt¹øÿþ +þÿ•Ê•‘È‘ÑèÑòÿ¨¨ÓŠŠÅþÿÂÂà×ÿþ +ˆ»±ç3.©Ô©¤Ñ¤ÕêÕ0—0€¿€f³f¶Ú¶ûÿùüùr¹rÀßÀ[[&“&ðûíÛÙïqq¸øÿþ +ˆ»±ç3.ªÕª¤Ñ¤ØëØ*”*Àj´jÁßÁøÿÁ»Ü»€À€A A×îÔÝÚñqq¸øÿþ +÷÷ûýýþôôúüüþýþ××ë††ÂøÿUUª££Ñþÿòòøüüýññøööú÷÷ú==Ÿõÿýþýþþþÿíöíìÿþýþÿýþýûýûûÿóùó©Ô©ªÕªåòåòÿŽŽÇkkµøÿþ +‰»±ç3.¬Ö¬£Ñ£¼Ý¼ À‹Å‹ï÷ïøÿ¡Ð¡ºÜºa°a<<ÅåÂÝÙòtt¹øÿþ +þÿ”Ê”ÈÒèÒòÿ¨¨ÓŽŽÇþÿÇÇâ×ÿþ +ˆ»±ç3.©Ô©¤Ñ¤ÕêÕ1˜1€¿€e²e´Ù´ûÿøûøp¸p»Ý»‡Ã‡9œ9×îÔÝÚñqq¸øÿþ +‰»±ç3.¬Ö¬£Ñ£·Û· ÀÇòøòøÿ}¾}ãñãŒÆŒg³gh·eæÝútt¹øÿþ +‡»±ç3.¨Ô¨¤Ñ¤ÓéÓ8›8¿a°a¨Ó¨ûÿñøñÉäÉz¼z;;þÿûÿøØ×ìpp·øÿþ +‰»±ç3.¬Ö¬¤Ñ¤ÛíÛŽƒÁƒr¸rØëØøÿ¢Ñ¢ºÜºs¹sK¥KÕíÒÞÛòss¹øÿþ +‰»±ç3.¬Ö¬£Ñ£²Ø²!!€¿€“É“öúöøÿ¡Ð¡ºÜº\®\7›7Àã½ÝÙòtt¹øÿþ + +„©©Ôøÿ Ð ÇþÿÀ¾ß¾ÎÊåÊÙìÙøÿm¶mþÿœÍœw»wÒéÒÖêÖõÿ€À€¾ß¾ÏçÏuºuùýøþýþFF£þÿ +‡»±ç3.¨Ô¨¤Ñ¤ÔéÔ5š5¿b±b¬Õ¬ûÿôùôÇãÇ¿;œ;þÿýÿúØ×ìpp·øÿþ +‰»±ç3.¬Ö¬¤Ñ¤ÖëÖŽƒÁƒvºvÛíÛøÿ¢Ñ¢¿Þ¿6š6ûÿØØëtt¹øÿþ +‰»±ç3.¬Ö¬£Ñ£Âà À†Ã†êôêøÿÆâÆr¸rkµk?Ÿ?ÈçÅÞÚòtt¹øÿþ +±±ÿÖÖÿÒÒÿŽŽýÿ +ÆÆÿÿééÿŽŽèÿþ +%%EndData +end +%%PageTrailer +%%Trailer +%%BoundingBox: 0 0 211 683 +%%HiResBoundingBox: 0 0 211 683 +%%EOF diff --git a/doc/figs/mebroot_obfdel_01.png b/doc/figs/mebroot_obfdel_01.png new file mode 100644 index 00000000..018ea0a4 --- /dev/null +++ b/doc/figs/mebroot_obfdel_01.png Binary files differdiff --git a/doc/figs/msgbox.eps b/doc/figs/msgbox.eps new file mode 100644 index 00000000..c8e8e613 --- /dev/null +++ b/doc/figs/msgbox.eps Binary files differdiff --git a/doc/figs/msgbox.png b/doc/figs/msgbox.png new file mode 100644 index 00000000..8987d6d8 --- /dev/null +++ b/doc/figs/msgbox.png Binary files differdiff --git a/doc/figs/pe_format.eps b/doc/figs/pe_format.eps new file mode 100644 index 00000000..fe9b5ee0 --- /dev/null +++ b/doc/figs/pe_format.eps Binary files differdiff --git a/doc/figs/pe_format.gif b/doc/figs/pe_format.gif new file mode 100644 index 00000000..4757f19e --- /dev/null +++ b/doc/figs/pe_format.gif Binary files differdiff --git a/doc/figs/xxx_mnemo01.eps b/doc/figs/xxx_mnemo01.eps new file mode 100644 index 00000000..da39ef98 --- /dev/null +++ b/doc/figs/xxx_mnemo01.eps Binary files differdiff --git a/doc/figs/xxx_mnemo01.png b/doc/figs/xxx_mnemo01.png new file mode 100644 index 00000000..541112e4 --- /dev/null +++ b/doc/figs/xxx_mnemo01.png Binary files differdiff --git a/doc/figs/xxx_mnemo02.eps b/doc/figs/xxx_mnemo02.eps new file mode 100644 index 00000000..2db59b92 --- /dev/null +++ b/doc/figs/xxx_mnemo02.eps Binary files differdiff --git a/doc/figs/xxx_mnemo02.png b/doc/figs/xxx_mnemo02.png new file mode 100644 index 00000000..2bf7bdeb --- /dev/null +++ b/doc/figs/xxx_mnemo02.png Binary files differdiff --git a/doc/figs/xxx_mnemo03.eps b/doc/figs/xxx_mnemo03.eps new file mode 100644 index 00000000..9ab49443 --- /dev/null +++ b/doc/figs/xxx_mnemo03.eps Binary files differdiff --git a/doc/figs/xxx_mnemo03.png b/doc/figs/xxx_mnemo03.png new file mode 100644 index 00000000..760970f7 --- /dev/null +++ b/doc/figs/xxx_mnemo03.png Binary files differdiff --git a/doc/figs/xxx_mnemo04.eps b/doc/figs/xxx_mnemo04.eps new file mode 100644 index 00000000..ab74529d --- /dev/null +++ b/doc/figs/xxx_mnemo04.eps Binary files differdiff --git a/doc/figs/xxx_mnemo04.png b/doc/figs/xxx_mnemo04.png new file mode 100644 index 00000000..83610c7e --- /dev/null +++ b/doc/figs/xxx_mnemo04.png Binary files differdiff --git a/doc/figs/xxx_mnemo05.eps b/doc/figs/xxx_mnemo05.eps new file mode 100644 index 00000000..f636c3ed --- /dev/null +++ b/doc/figs/xxx_mnemo05.eps Binary files differdiff --git a/doc/figs/xxx_mnemo05.png b/doc/figs/xxx_mnemo05.png new file mode 100644 index 00000000..fe407617 --- /dev/null +++ b/doc/figs/xxx_mnemo05.png Binary files differdiff --git a/doc/figs/xxx_mnemo06.eps b/doc/figs/xxx_mnemo06.eps new file mode 100644 index 00000000..dea835a8 --- /dev/null +++ b/doc/figs/xxx_mnemo06.eps Binary files differdiff --git a/doc/figs/xxx_mnemo06.png b/doc/figs/xxx_mnemo06.png new file mode 100644 index 00000000..fe422111 --- /dev/null +++ b/doc/figs/xxx_mnemo06.png Binary files differdiff --git a/doc/figs/xxx_mnemo07.eps b/doc/figs/xxx_mnemo07.eps new file mode 100644 index 00000000..6935c398 --- /dev/null +++ b/doc/figs/xxx_mnemo07.eps Binary files differdiff --git a/doc/figs/xxx_mnemo07.png b/doc/figs/xxx_mnemo07.png new file mode 100644 index 00000000..d6f620e4 --- /dev/null +++ b/doc/figs/xxx_mnemo07.png Binary files differdiff --git a/doc/figs/xxx_mnemo08.eps b/doc/figs/xxx_mnemo08.eps new file mode 100644 index 00000000..c1dbdc8e --- /dev/null +++ b/doc/figs/xxx_mnemo08.eps Binary files differdiff --git a/doc/figs/xxx_mnemo08.png b/doc/figs/xxx_mnemo08.png new file mode 100644 index 00000000..cfd200c6 --- /dev/null +++ b/doc/figs/xxx_mnemo08.png Binary files differdiff --git a/doc/figs/xxx_mnemo09.eps b/doc/figs/xxx_mnemo09.eps new file mode 100644 index 00000000..9e947f9c --- /dev/null +++ b/doc/figs/xxx_mnemo09.eps Binary files differdiff --git a/doc/figs/xxx_mnemo09.png b/doc/figs/xxx_mnemo09.png new file mode 100644 index 00000000..990ad13f --- /dev/null +++ b/doc/figs/xxx_mnemo09.png Binary files differdiff --git a/doc/figs/xxx_mnemo10.eps b/doc/figs/xxx_mnemo10.eps new file mode 100644 index 00000000..4b838013 --- /dev/null +++ b/doc/figs/xxx_mnemo10.eps Binary files differdiff --git a/doc/figs/xxx_mnemo10.png b/doc/figs/xxx_mnemo10.png new file mode 100644 index 00000000..3c985982 --- /dev/null +++ b/doc/figs/xxx_mnemo10.png Binary files differdiff --git a/doc/figs/xxx_vm01.eps b/doc/figs/xxx_vm01.eps new file mode 100644 index 00000000..e56ac93b --- /dev/null +++ b/doc/figs/xxx_vm01.eps Binary files differdiff --git a/doc/figs/xxx_vm01.png b/doc/figs/xxx_vm01.png new file mode 100644 index 00000000..fc1e7e15 --- /dev/null +++ b/doc/figs/xxx_vm01.png Binary files differdiff --git a/doc/slides.tex b/doc/slides.tex new file mode 100644 index 00000000..cf7057e7 --- /dev/null +++ b/doc/slides.tex @@ -0,0 +1,2243 @@ +\documentclass[ + beamer, +% handout, +% notes=show, +% notes=onlyslideswithnotes, +% notes=only, +% xcolor=pst, + dvips, +]{beamer} + +%\usepackage[francais]{babel} +\usepackage[latin1]{inputenc} +\usepackage{alltt} +\usepackage{pstricks} +\usepackage{pst-node} +\usepackage{listings} +\usepackage{xspace} +\usepackage{xcolor} + + +%Workarround some bugs in marvosym +\let\RescueRightarrow=\Rightarrow +\usepackage{marvosym} +\renewcommand{\Rightarrow}{\RescueRightarrow} + +\usepackage{marvosym} + +\usepackage{tikz} +\usetikzlibrary{matrix,calc,arrows,shapes,snakes,automata,backgrounds,petri,fit,positioning,chains} +\usepackage{verbatim} +\usepackage{bigcenter} +%%\usetikzlibrary{calc} +%%\usetikzlibrary[calc] +%%\usetikzlibrary{shapes,arrows} + +%%\usetikzlibrary{calc,arrows,shapes,snakes,automata,backgrounds,petri,fit} +%% +%%\usetikzlibrary{% +%% arrows,% +%% shapes.misc,% wg. rounded rectangle +%% shapes.arrows,% +%% chains,% +%% matrix,% +%% positioning,% wg. " of " +%% scopes,% +%% decorations.pathmorphing,% /pgf/decoration/random steps | erste Graphik +%% shadows,% +%% fit +%%} +%% + + +\usetikzlibrary{matrix} +\usetikzlibrary{calc,arrows,shapes,snakes,automata,backgrounds,petri,fit} + +\usetikzlibrary{% + arrows,% + shapes.misc,% wg. rounded rectangle + shapes.arrows,% + chains,% + matrix,% + positioning,% wg. " of " + scopes,% + decorations.pathmorphing,% /pgf/decoration/random steps | erste Graphik + shadows% +} + + +\lstset{ + basicstyle=\sffamily\color{darkgray}, + keywordstyle=\bfseries\color{purple}, + identifierstyle=\bfseries\color{black}, + commentstyle=\ttfamily\itshape\color{purple}, + stringstyle=\ttfamily\color{brown}, + moredelim=[is][\color{red}]{==>}{<==}, % overwrited by language setting +% moredelim=**[is][\normalsize]{|}{|}, % overwrited by language setting + stringspaces=true, + showstringspaces=false, + frame=leftline, + numbersep=5pt, + defaultdialect=Python, + language=Python +} + + + +\newcommand{\domain}{\textit} +\newcommand{\tool}{\textsl} + +\newcommand{\scite}[1]{{\footnotesize\cite{#1}}} + +\mode<all> +{ +% \usetheme{Singapore} + \usetheme{Warsaw} + \usecolortheme{crane} + \setbeamercovered{transparent} + \setbeamercolor{background canvas}{bg=} +} + +\setbeamertemplate{footline} +{% + \begin{beamercolorbox}{section in head/foot} + \insertshortauthor\hfill\insertshorttitle{}\hfill\insertframenumber/\inserttotalframenumber +% \vskip2pt\insertnavigation{\paperwidth}\vskip2pt + \end{beamercolorbox}% +} + + + +\mode<presentation> { +% \setbeamertemplate{background canvas}[vertical shading][bottom=blue!30,top=purple!10] +} + + + +\mode<handout> { +} + +\newenvironment{questionblock}{\begin{alertblock}}{\end{alertblock}} +\newenvironment{hintblock}{\begin{block}}{\end{block}} +\newenvironment{answerblock}{\begin{exampleblock}}{\end{exampleblock}} + + +\pgfdeclareimage[height=8mm]{logo-eads}{logo/eads} +\logo{\href{http://www.eads.net}{\pgfuseimage{logo-eads}}} + + +\AtBeginSubsection[] +{ + \begin{frame}<beamer>[shrink] + \frametitle{Outline} + \tableofcontents[currentsection,currentsubsection] + \end{frame} +} + + +%\AtBeginPart{\frame{\partpage}} + +\subject{Binary manipulation with Miasm } +\title{Miasm\\ +(incomprehensible documentation)} +\date{} + + + +\institute[EADS/SE/CS]{ + \texttt{serpilliere at droids-corp 0rg}\\ + EADS Corporate Research Center --- IW/SE/CS\\ + IT sec Lab\\ + Suresnes, FRANCE +} + + +%\beamerdefaultoverlayspecification{<+->} + +\begin{document} + + +\begin{frame} %-=-=-=-=-=- + \titlepage +\end{frame} + + +\begin{frame}[shrink] %-=-=-=-=-=- + \frametitle{Outline} + \tableofcontents +\end{frame} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%box style + +\tikzstyle{block} = [draw, fill=blue!20, rectangle, + minimum height=1em, minimum width=2em, + top color=white, bottom color=blue!20] + +\tikzstyle{block2} = [draw, fill=blue!20, rectangle, + minimum height=1em, minimum width=4em, + top color=white, bottom color=blue!20, + rounded corners=3mm] + +\tikzstyle{block3} = [draw, fill=blue!20, rectangle, + minimum height=2em, minimum width=2em, + top color=white, bottom color=blue!20, + rounded corners=3mm] + +\tikzset{usblayer/.style={ + rectangle,minimum size=6mm,% text width=10em, + very thick,draw=black!50, + top color=white,bottom color=black!20, + node distance = 2em, text centered, + font=\ttfamily}} + + +\tikzstyle{sum} = [draw, fill=blue!20, circle, node distance=1cm] +\tikzstyle{input} = [coordinate] +\tikzstyle{output} = [coordinate] +\tikzstyle{pinstyle} = [pin edge={to-,thin,black}] + + +\tikzset{pfield/.style={ + rectangle,minimum size=6mm, + very thick,draw=black!50, + top color=white,bottom color=black!20, + font=\ttfamily}} + + +\tikzset{conf/.style={ + rectangle,minimum size=6mm, text width=7em, + very thick,draw=black!50, + top color=white,bottom color=black!20, + node distance = 2em, text centered, + font=\ttfamily}} + +\tikzset{confep/.style={ + rectangle,minimum size=6mm, text width=3em, + very thick,draw=black!50, + top color=white,bottom color=black!20, + node distance = 2em, text centered, + font=\ttfamily}} + +\tikzset{usblayer/.style={ + rectangle,minimum size=6mm,% text width=10em, + very thick,draw=black!50, + top color=white,bottom color=black!20, + node distance = 2em, text centered, + font=\ttfamily}} + +\tikzset{epbox/.style={ + rectangle,minimum size=3mm, minimum width=6em, + very thick,draw=black!50, + top color=white,bottom color=black!20, + node distance = 0em, + text badly centered, + text width=8em, + font=\ttfamily}} + +\tikzset{bloc/.style={ + rectangle,minimum size=6mm, minimum width=7em, minimum height=2em, + very thick,draw=black!50, + top color=white,bottom color=black!20, + rounded corners, + font=\scriptsize}} + + + + + + +\section{Random manipulations} +\subsection{PE} + +\begin{frame}[fragile] + \frametitle{Elfesteem use} + + \begin{exampleblock}{EXE reading} + \begin{itemize} + \item EXE parsing + \item (MZ/PE/sections/Directories) + \end{itemize} + \end{exampleblock} + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> from elfesteem import * +>>> e = pe_init.PE(open('calc.exe', 'rb').read()) +# section offset size addr flags rawsize + 0 .text 00000400 0126b0 00001000 60000020 00012800 + 1 .data 00012c00 00101c 00014000 c0000040 00000a00 + 2 .rsrc 00013600 008a88 00016000 40000040 00008c00 + \end{lstlisting}} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{Accesses} + + \begin{exampleblock}{File view} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> e.content[:4] +'MZ\x90\x00' + \end{lstlisting}} + \end{exampleblock} + + \begin{exampleblock}{RVA view} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> e.drva[0x1000:0x1004] +'\xea"\xdaw' + \end{lstlisting}} + \end{exampleblock} + + \begin{exampleblock}{Virtual addesses view} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> e.virt[0x1001000:0x1001004] +'\xea"\xdaw' + \end{lstlisting}} + \end{exampleblock} + +\end{frame} + + + + +\begin{frame}[fragile] + \frametitle{EXE attributes} + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> e.DirImport +<Directory Import> + 0 <SHELL32.dll> <W-ImpDesc=76968/4294967295L/4294967295L/77378/4252> + 0 <148, ShellAboutW> + 1 <msvcrt.dll> <W-ImpDesc=77256/4294967295L/4294967295L/77664/4540> + 0 <82, __CxxFrameHandler> + 1 <71, _CxxThrowException> + 2 <824, wcstoul> + ... + \end{lstlisting}} + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> e.DirRes +<ID RT_ICON subdir: 90192 None> + <ID RT_CURSOR subdir: 90528 None> + <ID 1036 data: 91152 <ResDataEntry=91576/744/1252/0>> + <ID RT_BITMAP subdir: 90552 None> + <ID 1036 data: 91168 <ResDataEntry=92320/296/1252/0>> + <ID RT_ICON subdir: 90576 None> + ... + \end{lstlisting}} + +\end{frame} + + + + + +\begin{frame}[fragile] + \frametitle{Common manipulation} + + \begin{exampleblock}{EXE generation} + \begin{itemize} + \item EXE creation + \item Default characteristics + \end{itemize} + \end{exampleblock} + + \lstset{language=Python} + {\scriptsize\begin{lstlisting}[]{} +e = PE() +open('uu.bin', 'wb').write(str(e)) + \end{lstlisting}} +\end{frame} + + + +\begin{frame}[fragile] + \begin{exampleblock}{Add a section to a binary} + \begin{itemize} + \item read the binary + \item add a section + \item generate binary + \end{itemize} + \end{exampleblock} + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> e = PE(open('calc.exe', 'rb').read()) +# section offset size addr flags rawsize + 0 .text 00000400 0126b0 00001000 60000020 00012800 + 1 .data 00012c00 00101c 00014000 c0000040 00000a00 + 2 .rsrc 00013600 008a88 00016000 40000040 00008c00 +>>> s_XXX = e.SHList.add_section(name='XXX', addr = 0x20000, rawsize = 0x1000) +>>> open('out.bin', 'wb').write(str(e)) + +>>> PE(open('out.bin', 'rb').read()) +# section offset size addr flags rawsize + 0 .text 00000400 0126b0 00001000 60000020 00012800 + 1 .data 00012c00 00101c 00014000 c0000040 00000a00 + 2 .rsrc 00013600 008a88 00016000 40000040 00008c00 + 3 XXX 0001c200 001000 00020000 e0000020 00001000 + \end{lstlisting}} +\end{frame} + + + +\begin{frame}[fragile] + \begin{exampleblock}{Menu edition} + \begin{itemize} + \item read DirRes + \item find menu + \item modify + \item generate the binary + \end{itemize} + \end{exampleblock} + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> e = PE(open('calc.exe', 'rb').read()) +>>> e.DirRes.resdesc.resentries + 0 <ID RT_ICON subdir: 90192 None>ResEntry + 1 <ID RT_MENU subdir: 90272 None>ResEntry + ... +>>> menu = e.DirRes.resdesc.resentries[1] +>>> menu.subdir.resentries + 0 <ID 106 subdir: 90720 None>ResEntry + 1 <ID 107 subdir: 90744 None>ResEntry +... + +>>> e.Opthdr.Optehdr[pe.DIRECTORY_ENTRY_BOUND_IMPORT].rva = 0 +>>> e.Opthdr.Optehdr[pe.DIRECTORY_ENTRY_BOUND_IMPORT].size = 0 + +>>> e.DirRes.resdesc.resentries[1].subdir.resentries[1].\ + subdir.resentries[0].data.s[8:22:2] +'Edition' +>>> e.DirRes.resdesc.resentries[1].subdir.resentries[1].\ + subdir.resentries[0].data.s[8:22] = "\x00".join([x for x in 'Toto'])+'\x00' +>>> open('out.bin.exe', 'wb').write(str(e)) + \end{lstlisting}} +\end{frame} + + +\begin{frame} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=1\textwidth]{figs/calc_mod.eps} + \end{center} + \end{figure} +\end{frame} + + +\begin{frame} + \frametitle{Common case} + + \begin{exampleblock}{EXE generation} + \begin{itemize} + \item create an EXE + \item default characteristics + \item new text section with ``xC3'' (ret) + \item place entry point + \item add some imports + \item $\rightarrow$ The binary is ready + \end{itemize} + \end{exampleblock} + +\end{frame} + + +\begin{frame}[fragile] + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +e = PE() +mysh = "\xc3" +s_text = e.SHList.add_section(name = "text", addr = 0x1000, rawsize = 0x1000, data = mysh) +e.Opthdr.Opthdr.AddressOfEntryPoint = s_text.addr +new_dll = [({"name":"kernel32.dll", + "firstthunk":s_text.addr+0x100}, + ["CreateFileA", "SetFilePointer", "WriteFile", "CloseHandle"] + ) + , + ({"name":"USER32.dll", + "firstthunk":None}, + ["SetDlgItemInt", "GetMenu", "HideCaret"] + ) + ] +e.DirImport.add_dlldesc(new_dll) +s_myimp = e.SHList.add_section(name = "myimp", rawsize = 0x1000) +e.DirImport.set_rva(s_myimp.addr) +open('uu.bin', 'wb').write(str(e)) + \end{lstlisting}} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Ida listing:} + \tiny\begin{verbatim} + ;******************************************************************x + ; section 1 <text> x + ; virtual address 00001000 virtual size 00001000 x + ; file offset 00001000 file size 00001000 x + ;******************************************************************x + x + ;**************************** x + ; program entry point x + ;**************************** x + entrypoint: x + ret x + \end{verbatim} +\end{frame} + + + + + + +\subsection{Assembleur/Désassembleur} + + + + + +\begin{frame} + \frametitle{Miasm} + + \begin{block}{Goal} + \begin{itemize} + \item Asm/DisAsm x86/PPC/ARM + \item Work on multi sources + \item (str/shellcode txt/PE/ELF/.S) + \item assembly to intermediate language + \item emulate intermediate language (in an environment) + \item Snapshot/restore + \item library of emulation + \item ... + \end{itemize} + \end{block} + +\end{frame} + + +\begin{frame}[fragile] + \frametitle{Common cases} + + \begin{exampleblock}{Dis/Asm} + \begin{itemize} + \item work on bytes/asm text/container + \item mini integrated linker + \item graph generation + \item ... + \end{itemize} + \end{exampleblock} + + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> from x86_escape.x86_escape import * +>>> l = x86_mn.dis('\x90') +>>> str(l) +'nop ' +>>> x86_mn.asm('nop') +['\x90'] +>>> x86_mn.asm('inc eax') +['@', '\xff\xc0'] +>>> str(x86_mn.dis('@')) +'inc eax' +>>> str(x86_mn.dis('\xff\xC0')) +'inc eax' + \end{lstlisting}} +\end{frame} + + + +\begin{frame}[fragile] + \frametitle{assembling x86 bloc} + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +all_bloc, symbol_pool = parse_asm.parse_txt(x86_escape.x86mnemo,r''' +main: + push 0 + push title + push msg + push 0 + call test_call + ret +test_call: + nop + ret +title: +.string "My box" +msg: +.string "My msg!" +''') + + +#fix shellcode addr +symbol_pool.add(asmbloc.asm_label('base_address', 0)) +symbol_pool.getby_name("main").offset = 0 + +####graph sc#### +g = asmbloc.bloc2graph(all_bloc[0]) +open("graph.txt" , "w").write(g) + + \end{lstlisting}} +\end{frame} + +\begin{frame} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=1\textwidth]{figs/gen_graph.eps} + \end{center} + \end{figure} +\end{frame} + + + +\begin{frame}[fragile] + \frametitle{shell code generation} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +f = open('out.bin', 'wb') +for p in patches: + f.seek(p) + f.write(patches[p]) +f.close() + \end{lstlisting}} +\end{frame} + + +\begin{frame}[fragile] + \begin{block}{Dump hexa} + \tiny\begin{verbatim} +x00000000 6a 00 6a 18 6a 10 6a 00-e8 01 00 00 00 c3 90 c3 |j j?j?j ?? ???| +x00000010 4d 79 20 6d 73 67 21 00-4d 79 20 62 6f 78 00 |My msg! My box | + \end{verbatim} + \end{block} + \begin{block}{Disassemble} + \tiny\begin{verbatim} +x00000000 6a00 push 0x0 +x00000002 6a18 push 0x18 +x00000004 6a10 push 0x10 +x00000006 6a00 push 0x0 +x00000008 e801000000 call 0xe +x0000000d c3 ret +x0000000e 90 nop +x0000000f c3 ret + \end{verbatim} + \end{block} + +\end{frame} + + +\begin{frame} + \frametitle{In the next slide...} + + \begin{block}{PE generation} + \begin{itemize} + \item generate a working PE + \item with imports + \item some code + \item which displays a dialog box + \item ... + \end{itemize} + \end{block} + +\end{frame} + + +\begin{frame}[fragile] + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +#! /usr/bin/env python +from x86_escape import * +from elfesteem import * + +e = pe_init.PE() +s_text = e.SHList.add_section(name = "text", addr = 0x1000, rawsize = 0x100) +s_iat = e.SHList.add_section(name = "iat", rawsize = 0x100) +new_dll = [({"name":"USER32.dll","firstthunk":s_iat.addr}, ["MessageBoxA"])] + +e.DirImport.add_dlldesc(new_dll) +s_myimp = e.SHList.add_section(name = "myimp", rawsize = len(e.DirImport)) +e.DirImport.set_rva(s_myimp.addr) +all_bloc, symbol_pool = parse_asm.parse_txt(x86_escape.x86mnemo,r''' +main: + push 0 + push title + push msg + push 0 + call [MessageBoxA] + ret +title: +.string "My box" +msg: +.string "My msg!" +''') +symbol_pool.add(asmbloc.asm_label('base_address', 0)) +symbol_pool.getby_name("MessageBoxA").offset = e.DirImport.get_funcvirt('MessageBoxA') +symbol_pool.getby_name("main").offset = e.rva2virt(s_text.addr) +resolved_b, patches = asmbloc.asm_resolve_final(x86_escape.x86mnemo, all_bloc[0], symbol_pool, []) +for p in patches: + e.virt[p] = patches[p] +e.Opthdr.Opthdr.AddressOfEntryPoint = e.virt2rva(symbol_pool.getby_name("main").offset) +open('uu.bin', 'wb').write(str(e)) + \end{lstlisting}} + +\end{frame} + + +\begin{frame} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=0.3\textwidth]{figs/msgbox.eps} + \end{center} + \end{figure} +\end{frame} + +\subsection{Graphe} +\begin{frame} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=0.9\textwidth]{figs/gandalf_01.eps} + \end{center} + \end{figure} +\end{frame} + + +\subsection{Introduction to intermediate language} + +\begin{frame}[fragile] + \frametitle{Instruction semantic} + + \begin{block}{Intermediate language} + \begin{itemize} + \item the instruction is composed of operations + \item each operation is executed in parallel + \item example: cmpsb + \end{itemize} + \end{block} + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +def cmpsb(): + e= [] + e+=l_cmp(ExprMem(esi, 8), ExprMem(edi, 8)) + e.append(ExprAff(edi, ExprCond(df, ExprOp('+', edi, ExprInt(uint32(1))), ExprOp('-', edi, ExprInt(uint32(1)))))) + e.append(ExprAff(esi, ExprCond(df, ExprOp('+', esi, ExprInt(uint32(1))), ExprOp('-', esi, ExprInt(uint32(1)))))) + return e + \end{lstlisting}} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{cmpsb semantic} + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> from x86_escape import ia32_sem +>>> e = ia32_sem.cmpsb() +>>> for x in e: +... print str(x) +... +zf = (== (- @8[esi] @8[edi]) 0x0) +nf = (& (== 0x1 (>> (- @8[esi] @8[edi]) 0x7)) 0x1) +pf = (parity (- @8[esi] @8[edi])) +cf = (| (& (== (== 0x1 (>> @8[esi] 0x7)) 0x0) (== 0x1 (>> @8[edi] 0x7))) (& (== 0x1 (>> (- @8[esi] @8[edi]) 0x7)) (| (== (== 0x1 (>> @8[esi] 0x7)) 0x0) (== 0x1 (>> @8[edi] 0x7))))) +of = (| (& (== (== 0x1 (>> (- @8[esi] @8[edi]) 0x7)) 0x1) (& (== (== 0x1 (>> @8[esi] 0x7)) 0x0) (== 0x1 (>> @8[edi] 0x7)))) (& (== (== 0x1 (>> (- @8[esi] @8[edi]) 0x7)) 0x0) (& (== 0x1 (>> @8[esi] 0x7)) (== (== 0x1 (>> @8[edi] 0x7)) 0x0)))) +af = (== (& (- @8[esi] @8[edi]) 0x10) 0x10) +edi = df?((+ edi 0x1),(- edi 0x1)) +esi = df?((+ esi 0x1),(- esi 0x1)) + \end{lstlisting}} +\end{frame} + + + +\begin{frame}[fragile] + \frametitle{Manipulation example} + + \begin{block}{registers touched by an instruction} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> from analysis_helper import * +>>> r, w = get_rw(ia32_sem.cmpsb()) +>>> r, w +(set_expr[@8[edi], @8[esi], df, edi, esi], set_expr[zf, nf, pf, cf, of, af, edi, esi]) + \end{lstlisting}} + \end{block} +\end{frame} + +\section{Langage intermédiaire} +\subsection{Description du langage} + + +\begin{frame} + \begin{block}{Expressions} + \begin{itemize} + \item ExprInt: interger + \item ExprId: identifier (variable) + \item ExprAff: a = b + \item ExprCond: a?b:c + \item ExprMem: dword ptr [a] + \item ExprOp: op(a, b, ...) + \item ExprSlice: a[0:8] (bits) + \item ExprCompose: slices composition + \item ExprSliceTo: position in a composition + \end{itemize} + \end{block} +That's all. +\end{frame} + +\begin{frame}[fragile] + \begin{exampleblock}{Some expressions} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> from expression import * +>>> a = ExprId('A', 32) +>>> b = ExprId('B', 32) +>>> c = ExprId('C', 32) +>>> o = a+b +>>> print o +(A + B) +>>> print ExprAff(c, o) +C = (A + B) + \end{lstlisting}} + \end{exampleblock} + \begin{exampleblock}{Definition of some instructions} +\begin{tabular}{ l l } + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +def mov(a, b): + return [ExprAff(a, b)] + +def xchg(a, b): + e = [] + e.append(ExprAff(a, b)) + e.append(ExprAff(b, a)) + return e + \end{lstlisting}}& + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +def update_flag_zf(a): + cast_int = tab_uintsize[a.get_size()] + return [ExprAff(zf, ExprOp('==', + a, + ExprInt(cast_int(0))))] +def update_flag_nf(a): + return [ExprAff(nf, ExprOp('&', + get_op_msb(a), + ExprInt(tab_uintsize[a.get_size()](1))))] + \end{lstlisting}} +\end{tabular} + \end{exampleblock} +\end{frame} + + +\subsection{Module de simplification d'expression} +\begin{frame}[fragile] + \begin{block}{The language has simplification rules} + \begin{itemize} + \item X + Y - Y : X + \item - (-X) : X + \item X +int1 + int2 : X+int3 (=int1 + int2) + \item ... + \end{itemize} + \end{block} + +\begin{exampleblock}{Example} +\begin{tabular}{ l l } + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> print o +(A + B) +>>> p = o - b +>>> print p +((A + B) - B) +>>> print expr_simp(p) +A + \end{lstlisting}}& + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> q = (a - ExprInt(uint32(1))) + ExprInt(uint32(3)) +>>> print q +((A - 0x1) + 0x3) +>>> print expr_simp(q) +(A + 0x2) + \end{lstlisting}} +\end{tabular} +\end{exampleblock} +\end{frame} + +\subsection{Symbolic execution} +\begin{frame}[fragile] + \begin{block}{Assembly to intermediate language} + \begin{itemize} + \item expressions representing instructions are execution simultaneously + \item affectations are done into a memory representation + \item (a dictionary) + \item the key is the identifier (non reducible) + \end{itemize} + \end{block} + + \begin{block}{interpretation machine} + \begin{itemize} + \item It defines usable registers + \end{itemize} + {\tiny\begin{lstlisting}[]{} +machine = eval_abs({esp:init_esp, ebp:init_ebp, eax:init_eax, ebx:init_ebx, + ecx:init_ecx, edx:init_edx, esi:init_esi, edi:init_edi, + cs:ExprInt(uint32(9)), + zf : ExprInt(uint32(0)), nf : ExprInt(uint32(0)), + pf : ExprInt(uint32(0)), of : ExprInt(uint32(0)), + cf : ExprInt(uint32(0)), tf : ExprInt(uint32(0)),... + tsc1: ExprInt(uint32(0)), dr7:ExprInt(uint32(0)),...}, + mem_read_wrap, + mem_write_wrap, ) + + \end{lstlisting}} + \end{block} + +\end{frame} + + +\begin{frame}[fragile] + \begin{exampleblock}{Example} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> l = x86_mn.dis("\x43") +>>> print l +inc ebx +>>> ex = get_instr_expr(l, eip) +>>> for e in ex: +... print e +... +zf = ((ebx + 0x1) == 0x0) +nf = ((0x1 == ((ebx + 0x1) >> 0x1F)) & 0x1) +... +ebx = (ebx + 0x1) + \end{lstlisting}} + \end{exampleblock} + + \begin{exampleblock}{Example} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> machine = eval_abs(dict(init_state)) +>>> print machine.pool[ebx] +init_ebx +>>> my_eip, mem_dst = emul_full_expr(ex, l, ExprInt(uint32(0)), None, machine) +>>> print machine.pool[ebx] +(init_ebx + 0x1) +>>> print machine.pool[zf] +((init_ebx + 0x1) == 0x0) + \end{lstlisting}} + \end{exampleblock} +\end{frame} + +\section{Jit compilation} +\subsection{Principle} +\begin{frame} + + \begin{block}{Memory} + \begin{itemize} + \item The memory is defined by zones + \item size, accesses and data + \item (for example a binary section) + \item it maps \emph{real addresses} to \emph{virtual addresses} + \end{itemize} + \end{block} + \begin{block}{translation} + \begin{itemize} + \item the code is disassembled + \item translated on the fly using semantic representation + \item and intermediate code is generated to C code and compiled + \end{itemize} + \end{block} +\end{frame} + + +\begin{frame} + \begin{block}{Emulation exception} + \begin{itemize} + \item if a translated bloc is modified, it is deleted from cache + \item and regenerated if pc reach it again (cache miss) + \item if errors, python is called back to deal it + \item for example, we can emulate windows SEH mechanism + \item Emulation des api + \end{itemize} + \end{block} +\end{frame} + + + + +\begin{frame} +\begin{center} + +\begin{tikzpicture}[node distance = 1.2cm, auto] + + \node [bloc] (runtime) {RunTime}; + \node [bloc, xshift=2cm,yshift=-1.5cm] (disasm) at (runtime) {disassemble}; + \node [bloc, below of=disasm] (inter) {intermediate language}; + \node [bloc, below of=inter] (ccode) {C Code}; + \node [bloc, below of=ccode] (python) {Python module}; + + \node [bloc, xshift=-2cm,yshift=-1.5cm] (supprcode) at (runtime) {Suppr code}; + + \draw[->] (runtime) -- (disasm) node[midway] {cache miss}; + \draw[->] (disasm) -- (inter); + \draw[->] (inter) -- (ccode); + \draw[->] (ccode) -- (python); + \draw[->, looseness=1] (python) to [bend right=95] (runtime); + + \draw[->, looseness=3] (runtime) to [out = 135, in=35] (runtime); + + + \draw[->] (runtime) to [bend right=20] node[midway, left] {auto mod} (supprcode) ; + \draw[->] (supprcode) to [bend right=40] (runtime); + +\end{tikzpicture} +\end{center} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{C translation} + \lstset{language=C} + {\tiny\begin{lstlisting}[]{} +unsigned int bloc_0080400B(void) +{ + loc_0080400B: + //pop eax + vmcpu.eax_new = MEM_LOOKUP_32(vmcpu.esp); + vmcpu.esp_new = (((vmcpu.esp&0xffffffff) + (0x4&0xffffffff))&0xffffffff); + + if (vmcpu.vm_exception_flags > EXCEPT_NUM_UDPT_EIP) { + vmcpu.eip = 0x80400B; + return (unsigned int)vmcpu.eip; + } + + vmcpu.eax = vmcpu.eax_new; + vmcpu.esp = vmcpu.esp_new; + + if (vmcpu.vm_exception_flags) { + vmcpu.eip = (vmcpu.vm_exception_flags > EXCEPT_NUM_UDPT_EIP) ? 0x80400B : 0x80400C; + return (unsigned int)vmcpu.eip; + } + + loc_0080400C: + //mov ebx, eax + vmcpu.ebx_new = vmcpu.eax; + + if (vmcpu.vm_exception_flags > EXCEPT_NUM_UDPT_EIP) { + vmcpu.eip = 0x80400C; + return (unsigned int)vmcpu.eip; + } + \end{lstlisting}} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{translation, memory accesses} + + \begin{exampleblock}{Assembly code} + \lstset{language=[x86masm]Assembler} + {\tiny\begin{lstlisting}[]{} +movzx eax, ds:byte_410360[ecx] + \end{lstlisting}} + \end{exampleblock} + + \begin{exampleblock}{C code} + \lstset{language=C} + {\tiny\begin{lstlisting}[]{} +//movzx eax, byte ptr [ecx+{<asmlabel (unsigned int)&tab_00410340[0x20] >: 1}] +eax_new = (((0x0 & (0xFFFFFFFF>>(32-24))) << 8) | ((MEM_LOOKUP(8, (((ecx&0xffffffff) + + ((unsigned int)&tab_00410340[0x20]&0xffffffff))&0xffffffff)) & (0xFFFFFFFF>>(32-8))) << 0)); +eax = eax_new; + \end{lstlisting}} + \end{exampleblock} + + +\end{frame} + + +\subsection{Exemples jit} +\begin{frame}[fragile] + \frametitle{Demo: assembly code} +{\tiny\begin{semiverbatim} +objdump -D -b binary -m i386 -Maddr32,data32,intel sc_test.bin +sc_test.bin: file format binary +Disassembly of section .data: +00000000 <.data>: + 0: b8 ef be 37 13 mov eax,0x1337beef + 5: b9 04 00 00 00 mov ecx,0x4 + a: c1 c0 08 rol eax,0x8 + d: e2 fb loop 0xa + f: c3 ret + \end{semiverbatim}} +\end{frame} + + +\begin{frame}[fragile] + \begin{block}{Memory creation} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +code_ad = 0x20000 +vm_add_memory_page(code_ad, PAGE_READ|PAGE_WRITE|PAGE_EXEC, open("sc_test.bin").read()) +stack_base_ad = 0x1230000 +stack_size = 0x10000 +vm_add_memory_page(stack_base_ad, PAGE_READ|PAGE_WRITE, "\x00"*stack_size) +dump_memory_page_pool_py() + +regs = vm_get_gpreg() +regs['eip'] = code_ad +regs['esp'] = stack_base_ad+stack_size +vm_set_gpreg(regs) +dump_gpregs_py() + + \end{lstlisting}} + \end{block} + + \begin{exampleblock}{Result} + {\tiny\begin{semiverbatim} +Memory +ad 00020000 size 00000025 RWX hpad 0x8cd5000 +ad 01230000 size 00010000 RW_ hpad 0x8ce8000 +Registers +eip 00020000 eax 00000000 ebx 00000000 ecx 00000000 edx 00000000 +esi 00000000 edi 00000000 esp 01240000 ebp 00000000 + \end{semiverbatim}} + \end{exampleblock} + +\end{frame} + +\begin{frame}[fragile] + \begin{block}{Memory creation} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +vm_push_uint32_t(0) +vm_push_uint32_t(0) +vm_push_uint32_t(0x1337beef) + +symbol_pool = asmbloc.asm_symbol_pool() + +known_blocs = {} +code_blocs_mem_range = [] + +log_regs = True +log_mn = True +must_stop = False +def run_bin(my_eip, known_blocs, code_blocs_mem_range): + while my_eip != 0x1337beef: + if not my_eip in known_blocs: + updt_bloc_emul(known_blocs, in_str, my_eip, symbol_pool, code_blocs_mem_range, log_regs = log_regs, log_mn = log_mn) + try: + my_eip = vm_exec_blocs(my_eip, known_blocs) + except KeyboardInterrupt: + must_stop = True + py_exception = vm_get_exception() + if py_exception: + raise ValueEror("except at", hex(my_eip)) + +print "start run" +run_bin(code_ad, known_blocs, code_blocs_mem_range) + \end{lstlisting}} + \end{block} + +\end{frame} + + + + +\begin{frame}[fragile] + + \begin{exampleblock}{Result} + {\tiny\begin{semiverbatim} + eax 00000000 ebx 0000... +mov eax, 0x1337BEEF ... + eax 1337BEEF ebx 0000... +mov ecx, 0x00000004 ... + eax 1337BEEF ebx 0000... +rol eax, 0x00000008 ... + eax 37BEEF13 ebx 0000... +loop loc_0002000A ... +loc_0002000A ... + eax 37BEEF13 ebx 0000... +rol eax, 0x00000008 ... + eax BEEF1337 ebx 0000... +loop loc_0002000A ... +loc_0002000A ... + eax BEEF1337 ebx 0000... +rol eax, 0x00000008 ... + eax EF1337BE ebx 0000... +loop loc_0002000A ... +loc_0002000A ... + eax EF1337BE ebx 0000... +rol eax, 0x00000008 ... + eax 1337BEEF ebx 0000... +loop loc_0002000A ... +loc_0002000F ... + eax 1337BEEF ebx 0000... +ret + \end{semiverbatim}} + \end{exampleblock} + +\end{frame} + + + + + +\begin{frame}[fragile] + \begin{block}{Interaction} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +>>> vm_get_gpreg() +{'eip': 322420463, 'esp': 19136504, 'edi': 0, 'eax': 322420463, + 'ebp': 0, 'edx': 0, 'ebx': 0, 'esi': 0, 'ecx': 0} +>>> vm_get_str(code_ad, 0x10) +'\xb8\xef\xbe7\x13\xb9\x04\x00\x00\x00\xc1\xc0\x08\xe2\xfb\xc3' + \end{lstlisting}} + \end{block} + +\end{frame} + +\section{Exemples} + + + +\subsection{Hooks, gadget finder, ...} + +\begin{frame} + \begin{block}{Goal: hook in calc.exe} + \begin{itemize} + \item spot interesting code + \item find characteristic code + \item generate a hook + \end{itemize} + \end{block} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Code search} + { + \tiny\begin{verbatim} +#op code call[XXX] +p = "\xFF\x15"+ struct.pack('L', ad_setwtext) +p = re.escape(p) +candidates = [x.start() for x in re.finditer(p, e.content)] +candidates = [e.off2virt(x) for x in candidates] + +#search func setdisplaytext +found = False +for c in candidates: + #ad = guess_func_start(e, c) + job_done = set() + symbol_pool = asmbloc.asm_symbol_pool() + try: + all_bloc = asmbloc.dis_bloc_all(x86_mn, in_str, c, job_done, symbol_pool) + except: + continue + #filter on setfocus caller + for b in all_bloc: + l = b.lines[-1] + if not l.m.name == "call" or not x86_afs.imm in l.arg[0]: + continue + if l.arg[0][x86_afs.imm] == ad_setfocus: + found = c +if not found: + raise ValueError("caanot finc setdisplaytext") +ad = guess_func_start(e, found) +print "setdisplaytext:", hex(ad) + \end{verbatim} + } +\end{frame} + + +\begin{frame}[fragile] + \frametitle{Hook example} + { + \tiny\begin{verbatim} +h.add_hook(aes_init_ad, + { + "1_aes_init_key":(0x20, "push ecx"), + }) +... +h.add_hook(rsa_enc_priv_ad, + { + "1_seckey":(0x140, 'push [esp+0x34]'), + "2_txt":(0x80, 'push [esp+0x34]'), + "3_mod":(0x80, 'push [esp+0x34]') + }) +... +h.add_hook(pwd_chk_ad, + {"1_pwd":(''' + push [ebp+8] + call [lstrlenA] + push eax''', 'push ecx'), + "2_stack":(0x80, 'push [esp+0x30]')}) + + \end{verbatim} + } +\end{frame} + + +\begin{frame}[fragile] + \frametitle{Hook creation} + { + \tiny\begin{verbatim} +h = hooks(in_str, symbol_pool, gen_data_log_code = False) + +hname = h.add_hook(ad, + { + "1_DONT_LOG":(''' + mov eax, [ebp+8] + cmp byte ptr [eax], 0x31 + jnz out + cmp byte ptr [eax+2], 0x33 + jnz out + cmp byte ptr [eax+4], 0x33 + jnz out + cmp byte ptr [eax+6], 0x37 + jnz out + cmp byte ptr [eax+6], 0x2c + jnz out + push 0 + push mtitle + push mtxt + push 0 + call [MessageBoxA] + + + out: + ''', 'push [esp+0x30]')}, + ['mtitle:\n.string "title"', 'mtxt:\n.string "txt"']) + \end{verbatim} + } +\end{frame} + +\begin{frame}[fragile] + \frametitle{Binary modification} + { + \tiny\begin{semiverbatim} +all_bloc = h.all_bloc + +symbol_pool.add(asmbloc.asm_label('base_address', 0)) +symbol_pool.getby_name("MessageBoxA").offset = e.DirImport.get_funcvirt('MessageBoxA') +symbol_pool.getby_name(hname).offset = e.rva2virt(sh_ad) + +symb_reloc = {} +\textcolor{blue}{#compilation du patch} +resolved_b, patches = asmbloc.asm_resolve_final(x86mnemo, all_bloc[0], symbol_pool, [(0, sh_ad+e.Opthdr.Opthdr.ImageBase)], symb_reloc) +add_rels = [] +\textcolor{blue}{#ajout des nouvelles relocations} +for l, rels in symb_reloc.items(): + for x in rels: + add_rels.append(e.virt2rva(x+l.offset)) +\textcolor{blue}{#ajout des nouveaux imports} +s_myimp = e.SHList.add_section(name = "myimp", rawsize = len(e.DirImport)) +e.DirImport.set_rva(s_myimp.addr) +\textcolor{blue}{#patch du binaire} +for p in patches: + e.virt[p] = patches[p] +\textcolor{blue}{#reconstruction du binaire} +open('calc_mod.exe', 'wb').write(str(e)) + \end{semiverbatim} + } +\end{frame} + +\begin{frame} +\frametitle{Go Go Gadget} + \begin{block}{Goal: find eip/esp control} + \begin{itemize} + \item binary mapping into memory + \item Memory creation + \item add context informations to a program + \item start interpretation: \begin{itemize} + \item sweep on each code address range + \item execution maximum 10 instruction (for instance) + \item analyzes symbolic memory + \item filter interesting results + \end{itemize} + \end{itemize} + \end{block} +\end{frame} + + +\begin{frame}[fragile] + \begin{exampleblock}{Loading of a binary dump} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +data = open(fname, 'rb').read() +in_str = bin_stream_vm() +init_memory_page_pool_py() +init_code_bloc_pool_py() +vm_add_memory_page(0x10000000, PAGE_READ|PAGE_WRITE, data) + \end{lstlisting}} + \end{exampleblock} + \begin{exampleblock}{variable creation} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +arg1 = ExprId('ARG1', 32, True) +arg2 = ExprId('ARG2', 32, True) +ret1 = ExprId('RET1', 32, True) + \end{lstlisting}} + \end{exampleblock} + \begin{exampleblock}{machine creation} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +machine = eval_abs({esp:init_esp, ebp:init_ebp, eax:init_eax, ebx:init_ebx, + ecx:init_ecx, edx:init_edx, esi:init_esi, edi:init_edi, + cs:ExprInt(uint32(9)), + zf : ExprInt(uint32(0)), nf : ExprInt(uint32(0)), + of : ExprInt(uint32(0)), cf : ExprInt(uint32(0)), + ... +\end{lstlisting}} + \end{exampleblock} +\end{frame} + + +\begin{frame}[fragile] + \begin{exampleblock}{add context execution} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +machine.eval_instr(push(arg2)) +machine.eval_instr(push(arg1)) +machine.eval_instr(push(ret1)) +machine.eval_instr(push(ebp)) +machine.eval_instr(mov(ebp, esp)) +machine.eval_instr(sub(esp, ExprInt(uint32(0x14)))) +machine.eval_instr(mov(eax, ExprMem(ebp + ExprInt(uint32(8))))) +machine.eval_instr(mov(edx, ExprMem(eax + ExprInt(uint32(12))))) +machine.eval_instr(mov(eax, ExprMem(ebp + ExprInt(uint32(12))))) +machine.eval_instr(mov(ExprMem(esp), eax)) +machine.eval_instr(push(ExprInt(uint32(0x1337beef)))) + \end{lstlisting}} +(it could have been emulated as well) + \end{exampleblock} + + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +print dump_reg(machine.pool) +eax ARG2 ebx init_ebx ecx init_ecx edx @32[(+ ARG1 0xC)] +esi init_esi edi init_edi esp (init_esp - 0x28) +ebp (init_esp - 0x10) zf ((init_esp - 0x24) == 0x0) + \end{lstlisting}} + +\end{frame} + +\begin{frame}[fragile] + \begin{exampleblock}{Filter results after symbolic execution} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +myesp = machine.pool[esp] +if not ('ARG' in str(myesp) or 'DATA' in str(myesp)): + continue +print "eip", my_eip +print "esp", myesp + \end{lstlisting}} + \end{exampleblock} + \begin{exampleblock}{Result} + {\tiny +\begin{verbatim} +0x10002ccf +eip @32[ARG2] +esp (ARG2 + 0x4) +Instructions: +xchg eax, esp +ret +\end{verbatim} + } + \end{exampleblock} +\end{frame} + + +\subsection{Conficker} +\begin{frame} + + \begin{block}{Binary protection} + \begin{itemize} + \item packed + \item the packer is split with indirect jmps + \end{itemize} + \end{block} + + \begin{block}{Result} + \begin{itemize} + \item Ida knowns each basic bloc + \item but cannot graph + \end{itemize} + \end{block} + + + \begin{exampleblock}{Quick Counter measure} + \begin{itemize} + \item find each indirect jumps + \item find destination + \item patch the binary + \end{itemize} + \end{exampleblock} + +\end{frame} + + +\begin{frame} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=1\textwidth]{figs/conficker_1.eps} + \end{center} + \end{figure} +\end{frame} + + + + + +\begin{frame}[fragile] + \frametitle{indirect jump patching, binary regeneration} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +e = pe_init.PE(open('conficker.ese', 'rb').read()) +s_text = e.getsectionbyname('.text') +s_data = e.getsectionbyname('.data') + +for ad in xrange(ad_start, ad_end-15): + l1 = x86_mn.dis(e.virt[ad:ad+15]) + if not l1: continue + if not l1.m.name == 'jmp': continue + if l1.prefix: continue + + a = l1.arg[0] + if not x86_afs.ad in a or not x86_afs.imm in a: + continue + dst_ptr = a[x86_afs.imm] + if not (data_start <= dst_ptr < data_end): continue + continue + + dst_ad = struct.unpack('L', e.virt[dst_ptr:dst_ptr+4])[0] + if not( ad_start <= dst_ad < ad_end): continue + + e.virt[ad] = '\x90'*l1.l + e.virt[ad] = "\xE9"+struct.pack('l', dst_ad-(ad-1+l1.l)) + +open('out.bin', 'wb').write(str(e)) + + \end{lstlisting}} +\end{frame} + +\begin{frame} + \frametitle{Result: graph ok, but direct basic blocs are still splitted} + \begin{figure}[htp] + \begin{center} + \includegraphics[height=0.9\textheight]{figs/conficker_2.eps} + \end{center} + \end{figure} +\end{frame} + + + +\begin{frame}[fragile] + \frametitle{Disassembling: main function} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} + +job_done = [] +symbol_pool = asmbloc.asm_symbol_pool() +all_bloc = asmbloc.dis_bloc_all(x86_mn, in_str, 0x100041f4, job_done, symbol_pool, follow_call = False, patch_instr_symb = False) + +#find call address +for b in all_bloc: + l = b.lines[-1] + if l.m.name != 'call': continue + + a = l.arg[0] + if not x86_afs.symb in a: continue + + dst,off = dict(a[x86_afs.symb]).popitem() + new_bloc = asmbloc.dis_bloc_all(x86_mn, in_str, off, job_done, symbol_pool, follow_call = False, patch_instr_symb = False) + all_bloc+=new_bloc + +lbl_start = symbol_pool.getby_offset(oep) +bloc_merge(all_bloc, symbol_pool, [lbl_start]) + \end{lstlisting}} +\end{frame} + +\begin{frame}[fragile] + \frametitle{clean binary regeneration} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +#code to PIC +for b in all_bloc: + del symbol_pool.s_offset[b.label.offset] + b.label.offset = None + +#patch entry point +all_bloc2, symbol_pool2 = parse_asm.parse_txt(x86_mn,r''' +dllentry: +jmp main +''') + +#fix shellcode addr +#symbol_pool.add(asmbloc.asm_label('base_address', 0)) +symbol_pool2.getby_name("main").offset = 0x10001000 +symbol_pool2.getby_name("dllentry").offset = 0x1000434B + +#merge our sc and disassembled function +all_bloc+=all_bloc2[0] +for x in symbol_pool2.s.keys(): + symbol_pool.add(symbol_pool2.s[x]) +... +open('out.bin', 'wb').write(str(e)) + \end{lstlisting}} +\end{frame} + + +\begin{frame} + \frametitle{Result} + \begin{figure}[htp] + \begin{center} + \includegraphics[height=0.9\textheight]{figs/conficker_3.eps} + \end{center} + \end{figure} +\end{frame} + +\begin{frame} + \frametitle{We can analyze import functions loader} + \begin{figure}[htp] + \begin{center} + \includegraphics[height=0.9\textheight]{figs/conficker_4.eps} + \end{center} + \end{figure} +\end{frame} + + + +\begin{frame}[fragile] + \frametitle{Dump and binary reconstruction} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +e = pe_init.PE() +e.Opthdr.Opthdr.ImageBase = 0x3a0000 + +data = open('_003A0000.mem', 'rb').read() +s_text = e.SHList.add_section(name = "text", addr = 0x0, data = data) +... +e.DirImport.add_dlldesc(new_dll) +s_myimp = e.SHList.add_section(name = "myimp", rawsize = len(e.DirImport)) +e.DirImport.set_rva(s_myimp.addr) + +open('out.bin', 'wb').write(str(e)) + \end{lstlisting}} +\end{frame} + +\begin{frame} + \frametitle{binary reconstruction} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=0.9\textwidth]{figs/conficker_5.eps} + \end{center} + \end{figure} +\end{frame} + + +\subsection{mebroot} + +\begin{frame} + \frametitle{Obfuscated packer} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=1\textwidth]{figs/mebroot_4.eps} + \end{center} + \end{figure} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=1\textwidth]{figs/mebroot_1.eps} + \end{center} + \end{figure} +\end{frame} + +\begin{frame} + \frametitle{Packer obscurci} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=1\textwidth]{figs/mebroot_2.eps} + \end{center} + \end{figure} +\end{frame} + + +\begin{frame} + + \begin{block}{Reconstruction} + \begin{itemize} + \item goal: find non analyzed code + \item Disassemble a bloc + \item guess fake jcc destination + \item group and simplify blocs + \item regenerate binary + \end{itemize} + \end{block} +\end{frame} + + +\begin{frame}[fragile] + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +def get_mebbloc_instr(e, b): + if not b.lines: + return None + if b.lines[-1].m.name != "jnz": + return None + if b.lines[-2].m.name != "pop": + return None + if b.lines[-3].m.name != "test": + return None + ... + asmbloc.dis_bloc(x86mnemo, in_str, b, ad, job_done, symbol_pool, follow_call = False, patch_instr_symb = False) +... +asmbloc.bloc_merge(master_bloc, symbol_pool, call_ad) + \end{lstlisting}} +\end{frame} + + +\begin{frame} + \frametitle{Code reconstruit} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=1\textwidth]{figs/mebroot_3.eps} + \end{center} + \end{figure} +\end{frame} + +\begin{frame} + \frametitle{re generated binary mapping} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=1\textwidth]{figs/mebroot_4.eps} + \end{center} + \end{figure} + \begin{figure}[htp] + \begin{center} + \includegraphics[width=1\textwidth]{figs/mebroot_5.eps} + \end{center} + \end{figure} + + +\end{frame} + +\begin{frame} + \frametitle{Entry point} + \begin{figure}[htp] + \begin{center} + \includegraphics[height=0.8\textheight]{figs/mebroot_6.eps} + \end{center} + \end{figure} +\end{frame} + + + +\begin{frame} + \frametitle{Analysis} + \begin{block}{Reconstruction} + \begin{itemize} + \item The binary brute force its own key (hash) + \item Decipher itself + \item and decompress + \end{itemize} + \end{block} + + \begin{exampleblock}{We could borrow its own code} + \begin{itemize} + \item Disassemble deciphering code + \item Disassemble decompression code + \item Generate C code + \item and execute it on another ciphered code + \end{itemize} + \end{exampleblock} + +\end{frame} + + + +\begin{frame}[fragile] + + \begin{exampleblock}{Deciphering function emulation} + {\tiny + \begin{verbatim} +bsize: 33858 +bufs 0x976a000 0xb4bac008 +starting... +dyn_call to B4E6B480 +dyn_call to B4E6B300 +nop func called +... +dyn_call to B4E6B480 +dyn_call to B4E6B300 +nop func called +dyn_call to B4E6B480 +dyn_call to B4E6B300 +nop func called +dyn_call to B4E6B480 +dyn_call to B4E6B300 +nop func called +88B308C5 88B308C5 +C4FB632B C4FB632B +AA94D763 AA94D763 +5C2BB68F 5C2BB68F +end +ret len 33858 + + \end{verbatim} +} + \end{exampleblock} + + +\end{frame} + +\begin{frame}[fragile] + + \begin{exampleblock}{Decompression function code} + {\tiny + \begin{verbatim} +bsize: 33858 +bufs 0x947b000 0xb46b1008 +starting... +dyn_call to B4AFC3F0 +func alloc 828B0 (ret B462E008) +dyn_call to B4AFC5F0 +dyn_call to B4AFC3F0 +func alloc 3E6C (ret 94AF600) +dyn_call to B4AFC9D0 +dyn_call to B4AFC350 +func free 94AF600 (from 401FB5) +ret: 'MZ\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xff\xff...' + \end{verbatim} +} + \end{exampleblock} + +\end{frame} + + + +\begin{frame} + \frametitle{Final step} + + \begin{exampleblock}{Second layer} + \begin{itemize} + \item The binary generate a new binary (driver) + \item It is packed as well + \item Redo previous steps + \item or use previous functions to decipher new binary + \end{itemize} + \end{exampleblock} + + \begin{figure}[htp] + \begin{center} + \includegraphics[width=1\textwidth]{figs/mebroot_7.eps} + \end{center} + \end{figure} +\end{frame} + + +\begin{frame} + \frametitle{Obfuscated functions} + \begin{figure}[htp] + \begin{center} + \includegraphics[height=0.8\textheight]{figs/mebroot_obf_01.eps} + \end{center} + \end{figure} +\end{frame} + + + +\tikzset{bloc/.style={ + rectangle,minimum size=6mm, minimum width=6em, + very thick,draw=black!50, + top color=white,bottom color=black!20, + rounded corners, + font=\scriptsize}} + + +\tikzset{mywave/.style={ + snake=expanding waves,segment length=2mm, segment angle=20}} + +\begin{frame} + +\begin{columns} + +\column{0.4\textwidth} + +\begin{bigcenter} +\begin{figure} +\scalebox{0.5}{ +\begin{tikzpicture}[node distance = 3cm,>=latex'] + \node [bloc] (b1) {b1}; + \node [bloc, below right of=b1] (b2) {b2}; + \node [bloc, below left of=b1] (b3) {b3}; + \node [bloc, below left of=b2] (b4) {b4}; + + \draw[->] (b1) -- (b2); + \draw[->] (b1) -- (b3); + \draw[->] (b2) -- (b4); + \draw[->] (b3) -- (b4); + +\end{tikzpicture} +} +\end{figure} +\end{bigcenter} +\column{0.4\textwidth} +\begin{bigcenter} +\scalebox{0.5}{ +\begin{tikzpicture}[node distance = 3cm,>=latex'] + \node [bloc] (b0) {\begin{minipage}{2cm}\begin{center}b0\\e = 0\end{center}\end{minipage}}; + + + \node [bloc, below of=b0] (dispatch) {dispatcher}; + + + \node [bloc, below left of=dispatch] (b2) {\begin{minipage}{2cm}\begin{center}b2\\e = 4\end{center}\end{minipage}}; + \node [bloc, left of=b2] (b1) {\begin{minipage}{2cm}\begin{center}b1\\e = [2,3]\end{center}\end{minipage}}; + \node [bloc, below right of=dispatch] (b3) {\begin{minipage}{2cm}\begin{center}b3\\e = 4\end{center}\end{minipage}}; + \node [bloc, right of=b3] (b4) {\begin{minipage}{2cm}\begin{center}b3\\e = ?\end{center}\end{minipage}}; + + + \draw[->] (b0) -- (dispatch); + \draw[->] (dispatch) -- (b1); + \draw[->] (dispatch) -- (b2); + \draw[->] (dispatch) -- (b3); + \draw[->] (dispatch) -- (b4); + + \draw[->] (b1) to [out = 135, in=180] (dispatch); + \draw[->] (b2) to [out = 135, in=180] (dispatch); + \draw[->] (b3) to [out = 45, in=0] (dispatch); + \draw[->] (b4) to [out = 45, in=0] (dispatch); + + + +\end{tikzpicture} +} +\end{bigcenter} +\end{columns} +\end{frame} + +\begin{frame} + \begin{block}{Reconstruction} + \begin{itemize} + \item disassemble a function + \item get semantic of each bloc + \item symbolic execution + \item get each bloc result of the automata + \item patch jcc + \item regenerate binary + \end{itemize} + \end{block} +\end{frame} + +\begin{frame} + \frametitle{Résultat} + \begin{figure}[htp] + \begin{center} + \includegraphics[height=0.8\textheight]{figs/mebroot_obfdel_01.eps} + \end{center} + \end{figure} +\end{frame} + + + +\subsection{VM Study} + +\begin{frame} + \frametitle{first layer} + \begin{block}{Packer} + \begin{itemize} + \item The binary is ciphered by layers. + \item Just create an environment and emulate it with miasm. + \end{itemize} + \end{block} + \begin{center} + \includegraphics[width=0.7\textwidth]{figs/xxx_vm01.eps} + \end{center} +\end{frame} + + +\begin{frame} + \frametitle{First disassembling of vm mnemonic parsing} + \begin{center} + \includegraphics[width=0.7\textwidth]{figs/xxx_mnemo02.eps} + \end{center} +\end{frame} + +\begin{frame} + \frametitle{Obfuscation} + \begin{center} + \includegraphics[width=1.0\textwidth]{figs/xxx_mnemo03.eps} + \end{center} +\end{frame} + +\begin{frame} + \begin{block}{Solution} + \begin{itemize} + \item Callback is the disassembler engine + \item symbolic execution of its parents + \item Test if jcc is always true/false + \item and delete fake edges + \end{itemize} + \end{block} + +\end{frame} + +\begin{frame} + \frametitle{Result: simplified mnemonic parser} +\begin{tabular}{p{5cm} p{5cm} } + \includegraphics[width=0.08\textwidth]{figs/xxx_mnemo08.eps} + & + \includegraphics[width=0.13\textwidth]{figs/xxx_mnemo09.eps} +\end{tabular} + +\end{frame} + +\begin{frame} + \frametitle{End of parser: instruction dispatcher} + \begin{center} + \includegraphics[width=0.8\textwidth]{figs/xxx_mnemo10.eps} + \end{center} +\end{frame} + + +\begin{frame}[fragile] + \begin{exampleblock}{symbolic execution: touched variables} + {\tiny\begin{semiverbatim} +eax = ((((@8[init_esi] ^ init_ebx[0:8]) - 0xA8) ^ 0x1)_to[0:8], 0x0_to[8:32]) +ebx = ((init_ebx[0:8] - (((@8[init_esi] ^ init_ebx[0:8]) - 0xA8) ^ 0x1))_to[0:8], init_ebx[8:32]_to[8:32]) +esi = (init_esi + 0x1) +DST @32[((((((@8[init_esi] ^ init_ebx[0:8]) - 0xA8) ^ 0x1)_to[0:8], 0x0_to[8:32]) * 0x4) + init_edi)] + \end{semiverbatim}} + \end{exampleblock} + \begin{block}{Note} + \begin{itemize} + \item We need to follow modifications of ebx, esi, edi in each vm mnemonic + \item Those modifications are needed to known where disassembling next mnemonic + \end{itemize} + \end{block} +\end{frame} + +\begin{frame} + \frametitle{Disassembling correction} + \begin{center} + \includegraphics[width=0.8\textwidth]{figs/xxx_mnemo04.eps} + \end{center} +\end{frame} + +\begin{frame} + \frametitle{Bloc grouping} + \begin{center} + \includegraphics[width=1.0\textwidth]{figs/xxx_mnemo05.eps} + \end{center} +\end{frame} + +\begin{frame} + \frametitle{More than 150 vm mnemonic} + \begin{center} + \includegraphics[width=1.0\textwidth]{figs/xxx_mnemo07.eps} + \end{center} +\end{frame} + +\begin{frame} + \frametitle{Bloc analysis: erf} + \begin{center} + \includegraphics[width=0.6\textwidth]{figs/xxx_mnemo06.eps} + \end{center} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{But symbolic execution (again :p)} +{\tiny\begin{semiverbatim} +Registers after a bloc execution + eax init_eax + ebx init_ebx + ecx (@16[init_esp]_to[0:16], init_ecx[16:32]_to[16:32]) + edx init_edx + esi init_esi + edi init_edi + esp (init_esp-0x2) + ebp init_ebp + +stack modification: + @16[(init_esp+0x2)] (@16[(init_esp+0x2)]<<(@8[init_esp]&0x1F)) + @32[(init_esp-0x2)] ((@8[init_esp]&0x1F)?(0x0,((@16[(init_esp+0x2)]>>(0x10-(@8[init_esp]&0x1F)))&0x1))_to[0:1], 0x1_to[1:2], (parity (@16[(init_esp+0x2)]<<(@8[init_esp]&0x1F)))_to[2:3], 0x0_to[3:4], (((init_esp+0x2)&0x10)==0x10)_to[4:5], 0x0_to[5:6], ((@16[(init_esp+0x2)]<<(@8[init_esp]&0x1F))==0x0)_to[6:7], ((0x1==((@16[(init_esp+0x2)]<<(@8[init_esp]&0x1F))>>0xF))&0x1)_to[7:8], 0x2_to[8:11], ((0x1==((@16[(init_esp+0x2)]<<(@8[init_esp]&0x1F))>>0xF))^((@16[(init_esp+0x2)]>>(0x10-(@8[init_esp]&0x1F)))&0x1))_to[11:12], 0x0_to[12:32]) + +Result: +\textcolor{blue}{a = pop16 +b = pop16 +push16(a<<b) +push32(eflag)} + \end{semiverbatim}} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{Another example} +{\tiny\begin{semiverbatim} +---------- 12 0x6fab03 ---------- +eax = @32[init_esp] +@32[(init_esp+0x4)] (@32[(init_esp+0x4)]-@32[init_esp]) +@32[init_esp] (flags(@32[(init_esp+0x4)]-@32[init_esp])) +---------- 13 0x6fb100 ---------- +eax = @32[init_esp] +esp = (init_esp+0x4) +@32[(init_esp+0x4)] (@32[(init_esp+0x4)]^@32[init_esp]) +---------- 15 0x6fb3b2 ---------- +@32[(init_edi+0x1C)] (@32[(init_edi+0x1C)]&0xFFFFFBFF) +---------- 19 0x6fb6b8 ---------- +ecx = @32[init_esp] +esp = (init_esp+0x4) +@32[(init_esp+0x4)] (@32[(init_esp+0x4)]<<(@8[init_esp]&0x1F)) +---------- 21 0x6fb97e ---------- +eax = @32[init_esp] +@32[init_esp] @32[@32[init_esp]] +---------- 24 0x6fc3d1 ---------- +eax = ((((@16[init_esi]_to[0:16], init_eax[16:32]_to[16:32])+init_ebx)^0x18EE5784)-0x12C0A81E) +ebx = (init_ebx^((((@16[init_esi]_to[0:16], init_eax[16:32]_to[16:32])+init_ebx)^0x18EE5784)-0x12C0A81E)) +edx = (init_edx^((((@16[init_esi]_to[0:16], init_eax[16:32]_to[16:32])+init_ebx)^0x18EE5784)-0x12C0A81E)) +esi = (init_esi+0x2) +---------- 28 0x6fc935 ---------- +... +esp = (init_esp-0x4) +@32[(init_esp+0x4)] (@32[(init_esp+0x4)] umul32_hi @32[init_esp]) +@32[init_esp] (@32[(init_esp+0x4)] umul32_lo @32[init_esp]) +@32[(init_esp-0x4)] (0x2_to[0:2], (parity init_edi)_to[2:3], 0x0_to[3:4], (((init_esp+0x4)&0x10)==0x10)_to[4:5], 0x0_to[5:6], (init_edi==0x0)_to[6:7], ((0x1==(init_edi>>0x1F))&0x1)_to[7:8], 0x2_to[8:32]) + \end{semiverbatim}} +\end{frame} + +\begin{frame}[fragile] + \begin{block}{Instruct the interpreter} + \begin{itemize} + \item \verb?@32[(init_edi+0x1C)]? is the vm eflagest le eflag de la vm + \item we replace \verb?@8[(init_edi+0x28)]?, by REG1, REG2, ... + \item we replace \verb?esp+X? by registers \verb?arg32_0?, ... + \end{itemize} + \end{block} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Instruction} + \lstset{language=Python} + {\tiny\begin{lstlisting}[]{} +known_vm_e = { + init_edi + ExprInt(uint32(0x1C)): regflag, + init_edi + ExprInt(uint32(0x20)): reg1, + init_edi + ExprInt(uint32(0x24)): reg2, + init_edi + ExprInt(uint32(0x28)): reg3, + init_edi + ExprInt(uint32(0x2C)): reg4, + init_edi + ExprInt(uint32(0x30)): reg5, + init_edi + ExprInt(uint32(0x34)): reg6, + init_edi + ExprInt(uint32(0x38)): reg7, + init_edi + ExprInt(uint32(0x3C)): reg8, + init_edi + ExprInt(uint32(0x40)): reg9, + + ExprMem(init_esp-ExprInt(uint32(4))): argm1_32, + ExprMem(init_esp-ExprInt(uint32(2))): argm1_16, + ExprMem(init_esp): arg0_32, + ExprMem(init_esp+ExprInt(uint32(4))): arg1_32, + ExprMem(init_esp, size = 16): arg0_16, + ExprMem(init_esp+ExprInt(uint32(2)), size=16): arg1_16, + ExprMem(init_esp, size = 8): arg0_08, + ExprMem(init_esp+ExprInt(uint32(4)), size=8): arg1_08, +} + \end{lstlisting}} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Results} +{\tiny\begin{semiverbatim} +---------- 143 0x70a4f5 ---------- +esp = (init_esp - 0x4) +arg-1_32 = @32[init_edx] +\textcolor{blue}{=> push 32@[edx]} +---------- 151 0x70b1e1 ---------- +eax = arg1_32 +ecx = (arg1_32_to[0:8], ((0x1 == (arg1_08 >> 0x7)) == 0x1)?(0x0,0xFFFFFFFF)_to[8:32]) +esp = (init_esp + 0x4) +arg1_32 = (arg1_32_to[0:8], ((0x1 == (arg1_08 >> 0x7)) == 0x1)?(0x0,0xFFFFFFFF)_to[8:32]) +\textcolor{blue}{=> pop dum + pop X + movsx X, X8 + push X} +---------- 154 0x70b8b4 ---------- +ecx = (arg0_16_to[0:16], init_ecx[16:32]_to[16:32]) +esp = (init_esp - 0x2) +arg1_16 = (arg1_16 a>> (arg0_08 & 0x1F)) +arg-1_16 = ... flags of op ... +\textcolor{blue}{=> push arg1_16 >> arg0_08 + push eflags} +---------- 158 0x70bb56 ---------- +esp = (init_esp - 0x4) +arg-1_32 = @32[reg4] +\textcolor{blue}{=> push @32[reg4]} +---------- 155 0x70ba09 ---------- +arg0_32 = (! arg0_32) +DST 0x6F88F1 +\textcolor{blue}{=> not @32[esp]} + \end{semiverbatim}} +\end{frame} + +\begin{frame} + \begin{block}{Multi bloc mnemonic} + \begin{itemize} + \item A mnemonic can have a complex graph + \item we can evaluate a bloc, and propagate its state to its sons + \item and so on + \item No loop for the moment + \end{itemize} + \end{block} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Result: multiple vm exit} +\begin{tabular}{p{5cm} p{5cm}} +\multicolumn{2}{c}{ teste si reg7 == 0x0} +\\ +{\tiny\begin{semiverbatim} + +\textcolor{blue}{---------- state 1 ----------} +eax = @32[(init_esp + 0x1C)] +ebx = @32[(init_esp + 0x10)] +ecx = @32[(init_esp + 0x18)] +edx = @32[(init_esp + 0x14)] +esi = arg1_32 +edi = arg0_32 +\textcolor{blue}{the vm does not unstack args} +esp = (init_esp + 0x28) +ebp = @32[(init_esp + 0x8)] +@32[reg5] = 0x0 +DST @32[(init_esp + 0x24)] + \end{semiverbatim}} +& +{\tiny\begin{semiverbatim} +\textcolor{blue}{---------- state 2 ----------} +eax = @32[(init_esp + 0x1C)] +ebx = @32[(init_esp + 0x10)] +ecx = @32[(init_esp + 0x18)] +edx = @32[(init_esp + 0x14)] +esi = arg1_32 +edi = arg0_32 +\textcolor{blue}{the vm unstack reg7 arguments} +esp = ((init_esp + @32[reg7]) + 0x28) +ebp = @32[(init_esp + 0x8)] +@32[reg7] = 0x0 +@32[reg5] = 0x0 +arg-1_32 = ((init_esp + @32[reg7]) + 0x24) +DST @32[(init_esp + 0x24)] + \end{semiverbatim}} +\end{tabular} +\end{frame} + +\end{document} + + diff --git a/example/asm_arm.py b/example/asm_arm.py new file mode 100755 index 00000000..b146a362 --- /dev/null +++ b/example/asm_arm.py @@ -0,0 +1,68 @@ +#! /usr/bin/env python + +from miasm.arch.arm_arch import arm_mn +from miasm.core.bin_stream import bin_stream +from miasm.core import parse_asm +from miasm.core import asmbloc +import struct + +my_mn = arm_mn + + +####filelogger sc#### + +all_bloc, symbol_pool = parse_asm.parse_txt(my_mn,r''' +toto: + STMFD SP!, {R0-R12, LR}^ + MOV R11, LR + MOV R11, R0, ROR 4 + STC P2,C3, [R5, 24]! + MOV R1, R0 + LDR R2, [PC, R0 ROR 0x2] + CMP R2, R3 + BLE tutu + ORR R0, R1, R2 + ORRLE R0, R0, R0 + ORR R0, R0, R0 + LDR R3, [R11, 0x98] + LDR R3, [R11, -0x98] + STMFD SP!, {R4-R6,R11,R12,LR,PC} + STMFD SP!, {R0-R12, SP, LR, PC} + LDMIA R9, {R9, R12} + BLE tutu + LDMFD SP, {R4-R8,R11,SP,PC} + +tutu: + LDMFD SP!, {R0-R12, LR} + BX LR +''') + +g = asmbloc.bloc2graph(all_bloc[0]) +open("graph.txt" , "w").write(g) + + + +for b in all_bloc[0]: + print b +symbol_pool.add(asmbloc.asm_label('base_address', 0x0)) +symbol_pool.getby_name("toto").offset = 0x0 + +resolved_b, patches = asmbloc.asm_resolve_final(my_mn, all_bloc[0], symbol_pool) +print patches + +f = open('uu.bin', 'w') +for p, v in patches.items(): + f.seek(p) + f.write(v) + +f.close() + +print 'DISASSEMBLE FILE' +data = open('uu.bin', 'rb').read() +in_str = bin_stream(data) +job_done = set() +symbol_pool = asmbloc.asm_symbol_pool() +all_bloc = asmbloc.dis_bloc_all(my_mn, in_str, 0, job_done, symbol_pool, follow_call = False, lines_wd = 20) +g = asmbloc.bloc2graph(all_bloc) +open("graph2.txt" , "w").write(g) + diff --git a/example/asm_x86.py b/example/asm_x86.py new file mode 100755 index 00000000..8e911676 --- /dev/null +++ b/example/asm_x86.py @@ -0,0 +1,76 @@ +#! /usr/bin/env python + +from miasm.arch.ia32_arch import * +from miasm.core.bin_stream import bin_stream +from miasm.core import parse_asm +from elfesteem import * + +from miasm.core import asmbloc +import struct + +my_mn = x86_mn + + + + +my_mn = x86_mn + +e = pe_init.PE() +e.SHList.add_section(name = "text", addr = 0x1000, rawsize = 0x4000) + +####filelogger sc#### +all_bloc, symbol_pool = parse_asm.parse_txt(my_mn,r''' +main: + jmp end +getstr: + pop ebp + push 0xb + pop eax + cdq + + push edx + mov cx, 0x632d + push cx + mov edi, esp + + push 0xAA68732f + push 0x6e69622f + mov ebx, esp + push edx + + push ebp + mov byte ptr [ebp+eend-mystr], dl + push edi + push ebx + mov byte ptr [ebx+7], dl + mov ecx, esp + int 0x80 +end: + call getstr +mystr: +.string "cat /etc/passwd> /tmp/ooo; ls;" +eend: + nop +''') + +#fix shellcode addr +symbol_pool.add(asmbloc.asm_label('base_address', 0x400000)) +symbol_pool.getby_name("main").offset = 0x401000 + +for b in all_bloc[0]: + print b +####graph sc#### +g = asmbloc.bloc2graph(all_bloc[0]) +open("graph.txt" , "w").write(g) + +print "symbols" +print symbol_pool +#dont erase from start to shell code padading +resolved_b, patches = asmbloc.asm_resolve_final(my_mn, all_bloc[0], symbol_pool) +print patches + +for offset, raw in patches.items(): + e.virt[offset] = raw + +open('uu.bin', 'wb').write(str(e)) + diff --git a/example/disas_and_graph.py b/example/disas_and_graph.py new file mode 100755 index 00000000..0763f824 --- /dev/null +++ b/example/disas_and_graph.py @@ -0,0 +1,79 @@ +#! /usr/bin/env python +import os +from elfesteem import * +from miasm.tools.pe_helper import * +from miasm.tools import seh_helper +from miasm.core import bin_stream +import inspect +from miasm.core import asmbloc +from miasm.core import parse_asm +from elfesteem import pe +from miasm.arch import ia32_arch +import pickle +import sys +fname = sys.argv[1] +dis_oep = True +print sys.argv +if len(sys.argv) >2: + ad_to_dis = int(sys.argv[2], 16) + dis_oep = False + + + +dll_dyn_funcs = {} +data = open(fname, 'rb').read() +if data.startswith("MZ"): + e = pe_init.PE(open(fname, 'rb').read()) + if dis_oep: + ad_to_dis = e.rva2virt(e.Opthdr.AddressOfEntryPoint) + in_str = bin_stream.bin_stream(e.virt) + try: + dll_dyn_funcs = get_import_address(e) + except: + print 'bug in import parsing' + + +elif data.startswith("\x7fELF") : + e = elf_init.ELF(open(fname, 'rb').read()) + if dis_oep: + ad_to_dis = e.Ehdr.entry + in_str = bin_stream.bin_stream(e.virt) + try: + dll_dyn_funcs = get_import_address_elf(e) + except: + print 'bug in import parsing' + +else: + in_str = bin_stream.bin_stream(data) + +print 'dis', fname, 'at', "0x%.8X"%ad_to_dis + + + +symbol_pool = asmbloc.asm_symbol_pool() +# test qt +from miasm.graph.graph_qt import graph_blocs + + + +#test symbols from ida +for (n,f), ad in dll_dyn_funcs.items(): + l = asmbloc.asm_label("%s_%s"%(n, f), ad) + print l + symbol_pool.add(l) + + +def my_disasm_callback(ad): + all_bloc = asmbloc.dis_bloc_ia32(in_str, ad, symbol_pool = symbol_pool) + for b in all_bloc: + for l in b.lines: + for i, a in enumerate(l.arg): + if not ia32_arch.is_ad_lookup(a): + continue + x = a[ia32_arch.x86_afs.imm] + if x in symbol_pool.s_offset: + l.arg[i][x86_afs.symb] = symbol_pool.s_offset[x] + del(l.arg[i][ia32_arch.x86_afs.imm]) + return all_bloc + +graph_blocs(ad_to_dis, all_bloc = [], dis_callback = my_disasm_callback) diff --git a/example/sandbox_elf.py b/example/sandbox_elf.py new file mode 100644 index 00000000..7550cb20 --- /dev/null +++ b/example/sandbox_elf.py @@ -0,0 +1,117 @@ +import os +from elfesteem import * +from miasm.tools.pe_helper import * +from miasm.tools import seh_helper +import inspect +from miasm.core import asmbloc +from miasm.core import parse_asm +from miasm.tools.to_c_helper import * +from elfesteem import pe +import cProfile +import code +import sys +from miasm.tools import nux_api + + +# test sandboxing pp100_05ad9efbc4b0c16f243 + +fname = sys.argv[1] +e = elf_init.ELF(open(fname, 'rb').read()) +in_str = bin_stream_vm() +vm_init_regs() +init_memory_page_pool_py() +init_code_bloc_pool_py() + +codenat_tcc_init() + +filename = os.environ.get('PYTHONSTARTUP') +if filename and os.path.isfile(filename): + execfile(filename) + +vm_load_elf(e) + +runtime_lib, lib_dyn_funcs = preload_elf(e, patch_vm_imp = True, lib_base_ad = 0x77700000) +lib_dyn_ad2name = dict([(x[1], x[0]) for x in lib_dyn_funcs.items()]) +dyn_func = {} + + +stack_base_ad = 0x1230000 +stack_size = 0x10000 +vm_add_memory_page(stack_base_ad, PAGE_READ|PAGE_WRITE, "\x00"*stack_size) +dump_memory_page_pool_py() + + + +ep = e.sh.symtab.symbols['main'].value + +ptr_esp = stack_base_ad+stack_size-0x1000 +vm_set_mem(ptr_esp, "/home/toto\x00") +ptr_arg0 = ptr_esp +ptr_esp -=0x100 +ptr_args = ptr_esp +vm_set_mem(ptr_args, struct.pack('LL', ptr_arg0, 0)) + +regs = vm_get_gpreg() +regs['eip'] = ep +regs['esp'] = ptr_esp +vm_set_gpreg(regs) +dump_gpregs_py() + +vm_push_uint32_t(ptr_args) +vm_push_uint32_t(1) +vm_push_uint32_t(0x1337beef) + +dump_memory_page_pool_py() + +symbol_pool = asmbloc.asm_symbol_pool() + +my_eip = ep + + +known_blocs = {} +code_blocs_mem_range = [] + + +log_regs = False +log_mn = log_regs +must_stop = False +def run_bin(my_eip, known_blocs, code_blocs_mem_range): + global log_regs, log_mn + last_blocs = [None for x in xrange(10)] + cpt = 0 + while True: + #dyn lib funcs + if my_eip in runtime_lib.fad2cname: + fname = runtime_lib.fad2cname[my_eip] + if not fname in nux_api.__dict__: + raise ValueError('unknown api', (hex(vm_pop_uint32_t()), hex(my_eip), fname, hex(cpt))) + nux_api.__dict__[fname]() + regs = vm_get_gpreg() + my_eip = regs['eip'] + + continue + + + if not my_eip in known_blocs: + last_blocs.pop(0) + last_blocs.append(my_eip) + updt_bloc_emul(known_blocs, in_str, my_eip, symbol_pool, code_blocs_mem_range, log_regs = log_regs, log_mn = log_mn) + + + try: + my_eip = vm_exec_blocs(my_eip, known_blocs) + except KeyboardInterrupt: + must_stop = True + py_exception = vm_get_exception() + if py_exception: + print hex(my_eip) + if py_exception & EXCEPT_CODE_AUTOMOD: + print 'automod code' + dump_gpregs_py() + known_blocs, code_blocs_mem_range = updt_automod_code(known_blocs) + else: + print "unknown exception", py_exception + break + +print "start run" +run_bin(my_eip, known_blocs, code_blocs_mem_range) diff --git a/example/sandbox_pe.py b/example/sandbox_pe.py new file mode 100644 index 00000000..1b6457be --- /dev/null +++ b/example/sandbox_pe.py @@ -0,0 +1,125 @@ +import os +from elfesteem import * +from miasm.tools.pe_helper import * +import inspect +from miasm.core import asmbloc +from miasm.core import parse_asm +from miasm.tools.to_c_helper import * +from elfesteem import pe +import cProfile +import code +from miasm.tools import emul_helper +import sys +from miasm.tools import win_api +from miasm.arch.ia32_arch import * + + +def whoami(): + return inspect.stack()[1][3] + + +fname = sys.argv[1] +e = pe_init.PE(open(fname, 'rb').read()) + + +# /!\ no seh set for this demo + +vm_init_regs() +init_memory_page_pool_py() +init_code_bloc_pool_py() +in_str = bin_stream_vm() + +codenat_tcc_init() + +vm_load_pe(e) + +filename = os.environ.get('PYTHONSTARTUP') +if filename and os.path.isfile(filename): + execfile(filename) + + +runtime_dll, dll_dyn_funcs = preload_lib(e, patch_vm_imp = True, lib_base_ad = 0x7c811111) +# set winapi to ours +win_api.runtime_dll = runtime_dll + +dll_dyn_ad2name = dict([(x[1], x[0]) for x in dll_dyn_funcs.items()]) +dyn_func = {} + + +ep = e.rva2virt(e.Opthdr.AddressOfEntryPoint) + +stack_base_ad = 0x1230000 +stack_size = 0x10000 +vm_add_memory_page(stack_base_ad, PAGE_READ|PAGE_WRITE, "\x00"*stack_size) +dump_memory_page_pool_py() + + + + + +regs = vm_get_gpreg() +regs['eip'] = ep +regs['esp'] = stack_base_ad+stack_size +vm_set_gpreg(regs) +dump_gpregs_py() + +vm_push_uint32_t(0) +vm_push_uint32_t(0) +vm_push_uint32_t(0x1337beef) + +symbol_pool = asmbloc.asm_symbol_pool() + +known_blocs = {} +code_blocs_mem_range = [] + + +def dump_raw_e(e): + e.Opthdr.AddressOfEntryPoint = e.virt2rva(vm_get_gpreg()['eip']) + str_e = StrPatchwork(str(e)) + for s in e.SHList: + data = vm_get_str(e.rva2virt(s.addr), s.size) + svad = e.rva2virt(s.addr) + print hex(len(data)) + str_e[s.offset] = data + e.virt[e.off2virt(s.offset)] = data + open('out.bin', 'w').write(str(str_e)) + + +log_regs = True +log_mn = log_regs +def run_bin(my_eip, known_blocs, code_blocs_mem_range): + global log_regs, log_mn + while my_eip != 0x1337beef: + + #dyn dll funcs + if my_eip in runtime_dll.fad2cname: + fname = runtime_dll.fad2cname[my_eip] + if not fname in win_api.__dict__: + print repr(fname) + raise ValueError('unknown api', hex(vm_pop_uint32_t())) + win_api.__dict__[fname]() + regs = vm_get_gpreg() + my_eip = regs['eip'] + continue + + + if not my_eip in known_blocs: + updt_bloc_emul(known_blocs, in_str, my_eip, symbol_pool, code_blocs_mem_range, log_regs = log_regs, log_mn = log_mn) + try: + my_eip = vm_exec_blocs(my_eip, known_blocs) + except KeyboardInterrupt: + break + py_exception = vm_get_exception() + if py_exception: + if py_exception & EXCEPT_CODE_AUTOMOD: + print 'automod code' + dump_gpregs_py() + known_blocs, code_blocs_mem_range = updt_automod_code(known_blocs) + else: + raise ValueError("except at", hex(my_eip)) + + + +print "start emulation" +run_bin(ep, known_blocs, code_blocs_mem_range) +dump_raw_e(e) diff --git a/miasm/__init__.py b/miasm/__init__.py new file mode 100644 index 00000000..6c254425 --- /dev/null +++ b/miasm/__init__.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +__all__ = ['core/asmbloc', 'core/parse_asm', 'core/bin_stream', 'tools/pe_helper' ] diff --git a/miasm/arch/__init__.py b/miasm/arch/__init__.py new file mode 100644 index 00000000..acacfbeb --- /dev/null +++ b/miasm/arch/__init__.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +__all__ = ['ia32_reg'] diff --git a/miasm/arch/arm_arch.py b/miasm/arch/arm_arch.py new file mode 100644 index 00000000..c5fb574f --- /dev/null +++ b/miasm/arch/arm_arch.py @@ -0,0 +1,2054 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from numpy import uint8, uint16, uint32, uint64, int8, int16, int32, int64 +import shlex +import struct + +from miasm.arch.ia32_reg import x86_afs +from miasm.core.bin_stream import bin_stream + +tab_int_size = {int8:8, + uint8:8, + int16:16, + uint16:16, + int32:32, + uint32:32, + int64:64, + uint64:64 + } + +def hex2bin(op): + out = [] + for i in xrange(31, -1, -1): + out.append(str((op>>i)&1)) + for i in xrange(32, -1, -4): + out[i:i] = ' ' + return "".join(out) + +def myror(v, r): + return ((v&0xFFFFFFFFL)>>r) | ((v << (32-r))&0xFFFFFFFFL) +def myrol(v, r): + return ((v&0xFFFFFFFFL)>>(32-r)) | ((v << r)&0xFFFFFFFFL) + + +def str2imm(i): + if type(i) is list and len(i) == 1: + i = i[0] + if i.startswith('0x') or i.startswith('-0x'): + d =16 + else: + d = 10 + try: + a = int(i, d) + except: + return False + return a + +def imm2str(i): + if type(i) in [int, long]: + if i<0: + return "-0x%.x"%-i + else: + return "0x%.x"%i + return str(i) + +def is_imm(i): + if type(i) is list and len(i) == 1: + i = i[0] + if type(i) is list: + return False + + return type(str2imm(i)) is not bool + + + +def split_args(args): + t_enclosed = {'{':'}', '[':']', '(':')'} + t_v = ',' + def get_until_t(args, lvl): + o = [] + while args: + x = args.pop(0) + if x == lvl[-1]: + if len(lvl) == 1: + break + else: + lvl.pop() + if x != t_v: + o.append(x) + continue + + if x != t_v: + o.append(x) + if x in t_enclosed: + lvl.append(t_enclosed[x]) + continue + if x in t_enclosed.values(): + raise ValueError('unbalanced expr') + if lvl and lvl != [',']: + raise ValueError('unbalanced expr') + return o + + + o = [] + t = [x for x in shlex.shlex(args)] + while t: + a = get_until_t(t, [',']) + o.append(a) + return o + + + + +class bm(object): + class __metaclass__(type): + def __new__(cls, name, bases, odct): + if name is "bm": + return type.__new__(cls, name, bases, odct) + dct = {'fbits':None, 'l':None, "p_property":[], "checkinv" : False} + dct.update(odct) + + pname = None + if name.startswith('bm_'): + pname = name[3:] + dct["p_property"] = [pname]+dct["p_property"] + + + + b = bases[0] + + dct["check"] = b.check_no + l = dct["l"] + fbits = dct["fbits"] + if fbits: + l = len(fbits) + allbits = list(fbits) + allbits.reverse() + fbits = 0 + fmask = 0 + while allbits: + a = allbits.pop() + if a in '01': + a = int(a) + fbits<<=1 + fmask<<=1 + fbits|=[0, a][type(a) is int] + fmask|=[0, 1][type(a) is int] + dct["l"] = l + dct["fbits"] = fbits + #for bm int + if pname: + dct[pname] = fbits + dct['fmask'] = fmask + if dct['checkinv']: + dct["check"] = b.check_fbits_inv + else: + dct["check"] = b.check_fbits + + p_property = dct["p_property"] + + for p in p_property: + dct["get_"+p] = lambda self, p=p:getattr(self, p) + dct["set_"+p] = lambda self, p=p:setattr(self, p) + return type.__new__(cls, name, bases, dct) + + def __init__(self, parent, off, set_at = True): + self.parent = parent + self.off = off-self.l + def __repr__(self): + return "<W-"+str(self.__class__)+str(self.off+self.l-1)+" "+str(self.off)+">" + def check_no(self, v): + return True + def check_fbits(self, v): + return (v>>self.off) & self.fmask == self.fbits + def check_fbits_inv(self, v): + return (v>>self.off) & self.fmask != self.fbits + + def get_val(self, v): + return (v>>self.off) & ((1<<self.l)-1) + def set_val(self, v = None): + + if v == None and len(self.p_property) >= 1: + p = self.p_property[0] + v = getattr(self, p) + return (v&((1<<self.l)-1))<<self.off + + def bin(self): + return self.set_val() + + def parse(self, v): + if len(self.p_property) >= 1: + p = self.p_property[0] + val = self.get_val(v) + setattr(self, p, val) + return True + def setprop(self, val = None): + if len(self.p_property) >= 1: + p = self.p_property[0] + if not hasattr(self, p): + setattr(self, p, None) + + +COND_EQ = 0 +COND_NE = 1 +COND_CS = 2 +COND_CC = 3 +COND_MI = 4 +COND_PL = 5 +COND_VS = 6 +COND_VC = 7 +COND_HI = 8 +COND_LS = 9 +COND_GE = 10 +COND_LT = 11 +COND_GT = 12 +COND_LE = 13 +COND_AL = 14 +COND_NV = 15 + +class bm_cond(bm): + l = 4 + p_property = ["cond2str", 'str2cond'] + n = ['EQ', 'NE', 'CS', 'CC', 'MI', 'PL', 'VS', 'VC', 'HI', 'LS', 'GE', 'LT', 'GT', 'LE', 'AL', 'NV'] + + def cond2str(self): + return self.n[self.cond] + + def str2cond(self, cond): + if not cond in self.n: + raise ValueError('unknown cond') + self.cond = self.n.index(cond) + + +class bm_int0(bm): + fbits = '0' + +class bm_int1(bm): + fbits = '1' + +class bm_int00(bm): + fbits = '00' + +class bm_int01(bm): + fbits = '01' + +class bm_int000(bm): + fbits = '000' + +class bm_int011(bm): + fbits = '011' +class bm_int0111(bm): + fbits = '0111' + + +class bm_int01101(bm): + fbits = '01101' +class bm_int100(bm): + fbits = '100' + +class bm_int101(bm): + fbits = '101' + +class bm_int110(bm): + fbits = '110' + +class bm_int0000(bm): + fbits = '0000' + +class bm_int1001(bm): + fbits = '1001' + +class bm_int1110(bm): + fbits = '1110' + +class bm_int1111(bm): + fbits = '1111' + +class bm_int00001(bm): + fbits = '00001' + +class bm_int00010(bm): + fbits = '00010' + +class bm_int000000(bm): + fbits = '000000' + +class bm_accum(bm): + l = 1 + n = ['MUL', 'MLA'] + def name2str(self): + return self.n[self.accum] + + def str2name(self, name): + if not name in self.n: + raise ValueError('unknown name') + self.accum = self.n.index(name) + +class bm_immop(bm): + l = 1 + +class bm_opc(bm): + l = 4 + +class bm_opsz(bm): + l = 1 + +class bm_szext(bm): + l = 2 + +class bm_rot(bm): + l = 2 + +class bm_scc(bm): + l = 1 + p_property = ["scc2str"] + def scc2str(self): + return ['', 'S'][self.scc==1] + +class bm_lnk(bm): + l = 1 + p_property = ["lnk2str"] + def lnk2str(self): + return ['', 'L'][self.lnk==1] + +class bm_offs(bm): + l = 24 + + def parse(self, v): + val = self.get_val(v) + val<<=2 + if val & (1<<25): + val |=0xFC000000 + self.offs = val + return True + def bin(self): + if not type(self.offs) in [int, long]: + v = 0 + else: + v = (self.offs>>2)&0xffffff + return self.set_val(v) + +class bm_cooff(bm): + l = 8 + + def parse(self, v): + val = self.get_val(v) + val<<=2 + self.cooff = val + return True + def bin(self): + v = (self.cooff>>2)&0xff + return self.set_val(v) + +class bm_size(bm): + l = 1 + p_property = ["size2str"] + def size2str(self): + return ['', 'B'][self.size==1] + +class bm_tlen(bm): + l = 1 + +class bm_ppndx(bm): + l = 1 + +class bm_updown(bm): + l = 1 + +class bm_psr(bm): + l = 1 + +class bm_wback(bm): + l = 1 + +class bm_ldst(bm): + l = 1 + +class bm_reglist(bm): + l = 16 + + def parse(self, v): + val = self.get_val(v) + self.reglist = [] + for i in xrange(0x10): + if val & (1<<i): + self.reglist.append(i) + return True + def bin(self): + v = 0 + for r in self.reglist: + v|=(1<<r) + return self.set_val(v) + +class bm_rn(bm): + l = 4 + +class bm_rd(bm): + l = 4 + +class bm_rdh(bm): + l = 4 + +class bm_rdl(bm): + l = 4 + +class bm_rs(bm): + l = 4 + +class bm_rm(bm): + l = 4 + +class bm_crd(bm): + l = 4 + +class bm_crn(bm): + l = 4 + +class bm_crm(bm): + l = 4 + +class bm_cpnum(bm): + l = 4 + +class bm_cpopc(bm): + l = 4 + +class bm_opmode(bm): + l = 3 + +class bm_info(bm): + l = 3 + +class bm_swint(bm): + l = 24 + +class bm_op2(bm): + l = 12 + p_property = ["rm", "rot", "imm", "rs", 'shiftt', 'sub_shift_type', 'amount'] + + def parse(self, v): + val = self.get_val(v) + self.op2 = val + + if self.parent.immop: + self.rot = val>>8 + self.imm = val&0xff + else: + self.rm = val&0xf + self.shift = val>>4 + self.sub_shift_type = self.shift&1 + self.shift>>=1 + self.shiftt = self.shift&0x3 + self.shift>>=2 + + if self.sub_shift_type: + #sub shift type is reg + if self.shift&1: + return False + self.rs = self.shift>>1 + if self.rs==0: + return False + else: + #sub shift type is imm + self.amount = self.shift + + return True + + def bin(self): + if self.parent.immop: + val = self.rot<<8 + val+=self.imm&0xff + else: + shift = self.sub_shift_type + shift |= self.shiftt<<1 + if self.sub_shift_type: + shift|=self.rs<<4 + else: + shift|=self.amount<<3 + val = (shift<<4) | (self.rm&0xf) + + self.op2 = val + return self.set_val() + +class bm_opoff(bm): + l = 12 + p_property = ["rm", "imm", 'shiftt', 'amount'] + + def parse(self, v): + val = self.get_val(v) + self.opoff = val + + if self.parent.immop: + self.shift = val>>4 + self.rm = val&0xf + if self.shift&1: + #no reg shift + return False + + self.shift>>=1 + self.shiftt = self.shift&0x3 + self.amount = self.shift>>2 + else: + self.imm = val&0xfff + + return True + + def bin(self): + if self.parent.immop: + shift = 0 + shift |= self.shiftt<<1 + shift|=self.amount<<3 + val = (shift<<4) | (self.rm&0xf) + else: + val = self.imm&0xfff + + self.opoff = val + return self.set_val() + +class bm_undef1(bm): + l = 20 + +class bm_undef2(bm): + l = 4 + +class bmi_int1XX1(bm): + fbits = '0XXXXXXXXXXXXXXXXX1XX1' + checkinv = True + +class bmi_int1111(bm): + fbits = '1111' + checkinv = True + +class bmi_intX00X(bm): + fbits = '1XXXXXXXXXXXXXXXX1001' + checkinv = True + +class bmi_int11110XX1(bm): + fbits = 'X0XXXXXXXXXXXXX11110XX1' + checkinv = True + +class bm_int000100101111111111110001(bm): + fbits = '000100101111111111110001' + +class bm_int0001001011111111111100(bm): + fbits = '0001001011111111111100' + +class bmi_int1XXXX1(bm): + fbits = '1XXXXXXXXXXXXXXXXXXXX1' + checkinv = True + +class bm_sh(bm): + l = 2 + +class bm_hdoff1(bm): + l = 4 + +class bm_hdoff2(bm): + l = 4 + +class bm_sign(bm): + l = 1 + + +class arm_mnemo_metaclass(type): + rebuilt_inst = False + + def __call__(cls, op, offset = 0): + if type(op) in [int, long]: + cls = cls.class_from_op(op) + i = cls.__new__(cls) + i.__init__(op, offset) + elif type(op) is str: + cls = cls.asm(op) + i = cls.__new__(cls) + i.__init__(op, 0, False) + else: + raise ValueError('zarb arg') + return i + + def class_from_op(cls, op): + #print "dis", hex(op), hex2bin(op) + tab_mn = [arm_data, arm_mul, arm_mull, arm_swp, arm_brxchg, arm_hdtreg, arm_hdtimm, arm_sdt, arm_bdt, arm_br, arm_codt, arm_cort, arm_codo, arm_swi, arm_szext]#, arm_undef] + ret = filter(lambda x:x.check(op), tab_mn) + if len(ret)==1: + return ret[0] + raise ValueError('ambiquity %s'%str(ret)) + + + def dis(cls, bin, amode = None, sex = None): + if type(bin) == str: + bin = bin_stream(bin) + elif not isinstance(bin, bin_stream): + raise ValueError('unknown input') + + op = bin.readbs(4) + op = struct.unpack('<L', op)[0] + return cls(op, bin.offset-4) + + def asm_instr(cls, txt): + tab_mn = [arm_data, arm_mul, arm_mull, arm_swp, arm_brxchg, arm_hdtreg, arm_hdtimm, arm_sdt, arm_bdt, arm_br, arm_codt, arm_cort, arm_codo, arm_swi, arm_szext]#, arm_undef] + t = [x for x in shlex.shlex(txt)] + t.reverse() + name = t.pop() + ret = filter(lambda x:x.check_mnemo(name), tab_mn) + if len(ret)!=1: + raise ValueError('parse name err %s'%str(ret)) + cls = ret[0] + i = cls.__new__(cls) + i.__init__(txt, 0, False) + return i + + def asm(cls, txt, symbol_reloc_off = {}): + #print txt + i = cls.asm_instr(txt) + return [struct.pack('<L', i.bin())] + + def __new__(cls, name, bases, dct): + ret_c = type.__new__(cls, name, bases, dct) + if name is "arm_mn": + return ret_c + + mask = [] + if 'mask' in dct: + for off in dct['mask']: + mc = dct['mask'][off](None, off+1) + mask.append(mc) + + mask_orig = [bm_cond]+dct["mask_list"] + ret_c.mask_orig = mask_orig + off = 32 + for m in mask_orig: + mc = m(None, off) + off-=mc.l + mask.append(mc) + for pname in m.p_property: + ''' + p = property(lambda self=ret_c, pname=pname:getattr(getattr(self, "bm_"+pname), pname), + lambda self=ret_c, val=None,pname=pname:setattr(getattr(self, "bm_"+pname), pname, val)) + ''' + p = property(lambda self, pname=pname:getattr(getattr(self, "bm_"+pname), pname), + lambda self, val=None,pname=pname:setattr(getattr(self, "bm_"+pname), pname, val)) + + setattr(ret_c, pname, p) + + if off!=0: + raise ValueError('invalid mnemonic %d'%off) + ret_c.mask_chk = mask + + return ret_c + + def check(self, op): + for m in self.mask_chk: + if m.off<20 and m.fbits==None: + continue + if not m.check(op): + return False + return True + + def check_opts(self, rest): + if rest: + return False + return True + + def check_mnemo(self, mnemo): + found = False + for n in self.namestr: + if mnemo.startswith(n): + found = True + break + if not found: + return False + + rest = mnemo[len(n):] + for c in bm_cond.n: + if rest.startswith(c): + rest = rest[len(c):] + break + return self.check_opts(rest) + + def pre_parse_mnemo(self, args): + mn = [x for x in shlex.shlex(args)][0] + t = split_args(args[args.index(mn)+len(mn):]) + t = [mn]+t + t.reverse() + return t + + def parse_mnemo(cls, args): + t = cls.pre_parse_mnemo(args) + mn = t.pop() + t.reverse() + + + return [], mn, t + + + def parse_address(self, a): + o = {} + if len(a) != 1: + return a + if a[0] in regs_str+cop_str+copr_str: + return a + return {x86_afs.symb:{a[0]:1}} + + def prefix2hex(self, prefix): + return "" + + def has_symb(cls, a): + if type(a) in [int, long]+tab_int_size.keys(): + return False + if x86_afs.symb in a: + return True + return False + def get_symbols(cls, a): + if x86_afs.symb in a: + return a[x86_afs.symb].items() + return [] + def names2symbols(cls, a, s_dict): + all_s = a[x86_afs.symb] + for name, s in s_dict.items(): + count = all_s[name] + del(all_s[name]) + all_s[s] = count + def fix_symbol(cls, a, symbol_pool = None): + pass + def is_mem(cls, a): + pass + + def get_label(cls, a): + if x86_afs.ad in a and a[x86_afs.ad]: + return None + if x86_afs.imm in a: + return None + if not x86_afs.symb in a: + return None + n = a[x86_afs.symb] + if len(n)!=1: + return None + k = n.keys()[0] + if n[k] != 1: + return None + return k + +regs_str = ['R%d'%r for r in xrange(0x10)] +regs_str[13] = 'SP' +regs_str[14] = 'LR' +regs_str[15] = 'PC' + +cop_str = ['P%d'%r for r in xrange(0x10)] +copr_str = ['C%d'%r for r in xrange(0x10)] + +def reg2str(r): + return regs_str[r] +def str2reg(r): + if type(r) is list and len(r) == 1: + r = r[0] + return regs_str.index(r) + +def cop2str(r): + return cop_str[r] +def str2cop(r): + if type(r) is list and len(r) == 1: + r = r[0] + return cop_str.index(r) + +def copr2str(r): + return copr_str[r] +def str2copr(r): + if type(r) is list and len(r) == 1: + r = r[0] + return copr_str.index(r) + +def reglist2str(rlist): + out = [] + i = 0 + while i < len(rlist): + j = i+1 + while j < len(rlist) and rlist[j] <13 and rlist[j] == rlist[j-1]+1: + j+=1 + j-=1 + if j < i+2: + out.append(reg2str(rlist[i])) + i+=1 + else: + out.append(reg2str(rlist[i])+'-'+reg2str(rlist[j])) + i = j+1 + + return "{"+", ".join(out)+'}' + + +def str2reglist(rlist): + r_start = None + out = [] + rlist.pop() + while rlist: + tmp = rlist.pop() + if tmp =='-': + r_end = str2reg(rlist.pop()) + for i in xrange(r_start, r_end+1): + out.append(i) + r_start = None + elif tmp == '}': + if r_start!=None: + out.append(r_start) + break + elif r_start==None: + r_start = str2reg(tmp) + else: + out.append(r_start) + r_start = str2reg(tmp) + return out + +def args2reduce(args): + out = [] + for a in args: + if type(a) is list: + out+=args2reduce(a) + else: + out.append(a) + return out + +def arglist2str(args): + out = "" + for a in args: + if a in ['[', ']', 'LSL', 'LSR', 'ASR', 'ROR']: + out+=a+' ' + else: + out+=str(a) + out+=', ' + if out.endswith(', '): + out = out[:-2] + return out + + +def args2str(args): + return arglist2str(args2reduce(args)) + + +class arm_mn(object): + mask_list = [] + __metaclass__ = arm_mnemo_metaclass + def __init__(self, op, offset = 0, dis = True): + + off=32 + mask = [] + self.offset = offset + self.l = 4 + self.m = None + self.arg = [] + + + + for m in self.mask_orig: + mc = m(self, off) + off-=mc.l + for pname in m.p_property: + setattr(self, "bm_"+pname, mc) + mask.append(mc) + self.mask = mask + + if dis: + for m in self.mask: + ret = m.parse(op) + if not ret: + raise ValueError('cannot parse %.8X'%op) + else: + for m in self.mask: + ret = m.setprop() + + full_mnemo = arm_mn.pre_parse_mnemo(op) + mnemo = full_mnemo.pop() + name, cond, rest = self.parse_name_cond(mnemo) + self.name = name + self.cond = cond + self.parse_opts(rest) + self.str2name(name) + + self.parse_args(full_mnemo) + + def parse_opts(self, rest): + pass + def str2name(self, n): + pass + + def getname(self): + name = self.name2str() + cond = self.cond2str() + scc = "" + if cond =="AL":cond = "" #XXX smart display + + return name+cond+scc + + def bin(self): + v = 0 + for m in self.mask: + if not m.checkinv: + v|=m.bin() + return v + + def parse_name_cond(self, mnemo): + name, cond = None, None + for i, n in enumerate(self.namestr): + if mnemo.startswith(n): + name = n + break + if name == None: + raise ValueError('cannot parse name') + + rest = mnemo[len(n):] + for i, c in enumerate(bm_cond.n): + if rest.startswith(c): + cond = i + break + + if cond == None: + cond = COND_AL #default cond is AL + else: + rest = rest[len(c):] + return name, cond, rest + def breakflow(self): + return False + def splitflow(self): + return False + def dstflow(self): + return False + + def getnextflow(self): + return self.offset+self.l + + +MN_AND = 0 +MN_EOR = 1 +MN_SUB = 2 +MN_RSB = 3 +MN_ADD = 4 +MN_ADC = 5 +MN_SBC = 6 +MN_RSC = 7 +MN_TST = 8 +MN_TEQ = 9 +MN_CMP = 10 +MN_CMN = 11 +MN_ORR = 12 +MN_MOV = 13 +MN_BIC = 14 +MN_MVN = 15 + + +class arm_data(arm_mn): + mask_list = [bm_int00, bm_immop, bm_opc, bm_scc, bm_rn, bm_rd, bm_op2] + mask = {25:bmi_int1XX1, 26:bmi_int11110XX1} + + namestr = ['AND', 'EOR', 'SUB', 'RSB', 'ADD', 'ADC', 'SBC', 'RSC', 'TST', 'TEQ', 'CMP', 'CMN', 'ORR', 'MOV', 'BIC', 'MVN'] + allshifts = ['LSL', 'LSR', 'ASR', 'ROR'] + + def name2str(self): + return self.namestr[self.opc] + def str2name(self, n): + self.opc = self.namestr.index(n) + + @classmethod + def check_opts(cls, rest): + if rest in ['', 'S']: + return True + return False + + def args2str(self): + args = [] + if self.opc in [MN_MOV, MN_MVN]: + args.append(reg2str(self.rd)) + elif self.opc in [MN_CMP, MN_CMN, MN_TEQ, MN_TST]: + args.append(reg2str(self.rn)) + else: + args.append(reg2str(self.rd)) + args.append(reg2str(self.rn)) + + if self.immop: + #arg is pure imm + imm = myror(self.imm, self.rot*2) + args.append(imm2str(imm)) + else: + a = reg2str(self.rm) + if self.sub_shift_type: + #shift with another reg + a = [a, self.allshifts[self.shiftt], reg2str(self.rs)] + elif self.amount: #if no amount, no display needed + a = [a, self.allshifts[self.shiftt], imm2str(self.amount)] + args.append(a) + return args + + def __str__(self): + name = self.getname() + name+=self.scc2str() + args = self.args2str() + args = args2str(args) + return name+" "+args + + def parse_opts(self, opts): + self.scc = 0 + if not opts: + return + if opts[0] == "S": + self.scc = 1 + + def parse_args(self, args): + if self.opc in [MN_MOV, MN_MVN]: + self.rd = str2reg(args.pop()) + self.rn = 0 #default reg value + elif self.opc in [MN_CMP, MN_CMN, MN_TEQ, MN_TST]: + self.rn = str2reg(args.pop()) + self.rd = 0 #default reg value + else: + self.rd = str2reg(args.pop()) + self.rn = str2reg(args.pop()) + self.immop = [0,1][len(args) == 1 and is_imm(args[0])] + self.sub_shift_type = 0 + if self.immop: + #pure imm + + i = 0 + im = str2imm(args.pop()) + #find rol + while myrol(im, 2*i) > 0xFF: + i+=1 + if i > 16: + raise ValueError('cannot encod imm for shift!') + self.rot = i + self.imm = myrol(im, 2*i) + return + + self.rm = str2reg(args.pop()) + + #reg shift + self.shiftt=0 + self.amount = 0 + + if not args: + return + + if len(args) != 1: + raise ValueError('zarb arg1', args) + args = args.pop() + + #reg shift shift + if is_imm(args[-1]): + #shift reg shift num + self.sub_shift_type = 0 + self.amount = str2imm(args.pop()) + else: + #shift reg shift reg + self.sub_shift_type = 1 + self.rs = str2reg(args.pop()) + + self.shiftt = self.allshifts.index(args.pop()) + if args: + raise ValueError('zarb arg2', args) + + + + +class arm_mul(arm_mn): + mask_list = [bm_int000000, bm_accum, bm_scc, bm_rd, bm_rn, bm_rs, bm_int1001, bm_rm] + #cannot have pc in reg + namestr = ['MUL', 'MLA'] + def name2str(self): + return self.namestr[self.accum] + def str2name(self, n): + self.accum = self.namestr.index(n) + + @classmethod + def check_opts(cls, rest): + if rest in ['', 'S']: + return True + return False + + def args2str(self): + args = [] + args.append(reg2str(self.rd)) + args.append(reg2str(self.rm)) + args.append(reg2str(self.rs)) + if self.accum: + args.append(reg2str(self.rn)) + return args + + def __str__(self): + name = self.getname() + name+=self.scc2str() + args = self.args2str() + args = args2str(args) + return name+" "+args + + def parse_opts(self, opts): + self.scc = 0 + if not opts: + return + if opts[0] == "S": + self.scc = 1 + + def parse_args(self, args): + self.rd = str2reg(args.pop()) + self.rm = str2reg(args.pop()) + self.rs = str2reg(args.pop()) + if self.accum: + self.rn = str2reg(args.pop()) + else: + self.rn = 0 #default reg value + + +class arm_mull(arm_mn): + mask_list = [bm_int00001, bm_sign, bm_accum, bm_scc, bm_rdh, bm_rdl, bm_rs, bm_int1001, bm_rm] + #cannot habe pc as reg + namestr = ['UMULL', 'UMLAL', 'SMULL', 'SMLAL'] + def name2str(self): + return self.namestr[self.sign*2+self.accum] + def str2name(self, n): + tmp = self.namestr.index(n) + self.accum = tmp&1 + self.sign = tmp>>1 + + @classmethod + def check_opts(cls, rest): + if rest in ['', 'S']: + return True + return False + + def args2str(self): + args = [] + args.append(reg2str(self.rdh)) + args.append(reg2str(self.rdl)) + args.append(reg2str(self.rm)) + args.append(reg2str(self.rs)) + return args + + def __str__(self): + name = self.getname() + name+= self.scc2str() + args = self.args2str() + args = args2str(args) + return name+" "+args + + def parse_opts(self, opts): + self.scc = 0 + if not opts: + return + if opts[0] == "S": + self.scc = 1 + + def parse_args(self, args): + self.rdh = str2reg(args.pop()) + self.rdl = str2reg(args.pop()) + self.rm = str2reg(args.pop()) + self.rs = str2reg(args.pop()) + + +class arm_swp(arm_mn): + mask_list = [bm_int00010, bm_size, bm_int00, bm_rn, bm_rd, bm_int0000, bm_int1001, bm_rm] + mask = {19:bmi_int1111, 15:bmi_int1111, 3:bmi_int1111} + #cannot have PC as reg + namestr = ["SWP"] + def name2str(self): + return self.namestr[0] + + @classmethod + def check_opts(cls, rest): + if not rest or rest == 'B': + return True + return False + + def args2str(self): + args = [] + args.append(reg2str(self.rd)) + args.append(reg2str(self.rm)) + args.append(['[', reg2str(self.rn), ']']) + return args + + def __str__(self): + name = self.getname() + name+=self.size2str() + args = self.args2str() + args = args2str(args) + return name+' '+args + + def parse_opts(self, opts): + self.size = 0 + if not opts: + return + if opts[0] == "B": + self.size = 1 + + def parse_args(self, args): + self.rd = str2reg(args.pop()) + self.rm = str2reg(args.pop()) + p1 = args.pop() + self.rn = str2reg(args.pop()) + p2 = args.pop() + if p1== '[' and p2 ==']': + return + raise ValueError('cannot parse %s %s'%(str(p1), str(p2))) + +class arm_brxchg(arm_mn): + mask_list = [bm_int0001001011111111111100, bm_lnk, bm_int1, bm_rn] + + namestr = ["BX", "BXL"] + def name2str(self): + return self.namestr[self.lnk] + def str2name(self, n): + self.lnk = self.namestr.index(n) + + def parse_name_cond(self, mnemo): + name, cond = None, None + if not mnemo.startswith('BX'): + raise ValueError('zarb mnemo %s'%str(mnemo)) + l = len(mnemo) + if l in [2,4]: + n = mnemo[:2] + elif l in [3,4]: + n = mnemo[:3] + else: + raise ValueError('zarb mnemo %s'%str(mnemo)) + name = n + rest = mnemo[len(n):] + for i, c in enumerate(bm_cond.n): + if rest.startswith(c): + cond = i + break + if cond == None: + cond = COND_AL #default cond is AL + else: + rest = rest[len(c):] + return name, cond, rest + + @classmethod + def check_mnemo(self, mnemo): + if mnemo in self.namestr: + return True + return False + + + def args2str(self): + args = [] + args.append(reg2str(self.rn)) + return args + + def __str__(self): + name = self.getname() + args = self.args2str() + args = args2str(args) + return name+' '+args + + def parse_args(self, args): + self.rn = str2reg(args.pop()) + + def breakflow(self): + return True + def splitflow(self): + return self.cond != COND_AL + def dstflow(self): + return True + def getdstflow(self): + return [] + def setdstflow(self, dst): + return [] + def is_subcall(self): + return self.lnk + +class arm_hdtreg(arm_mn): + mask_list = [bm_int000, bm_ppndx, bm_updown, bm_int0, bm_wback, bm_ldst, bm_rn, bm_rd, bm_int00001, bm_sh, bm_int1, bm_rm] + #and XXX str cant be SB nor SH + mask = {24:bmi_intX00X} + + typestr = ["XXX", "H", "SB", "SH"] + namestr = ['STR', 'LDR'] + def name2str(self): + return self.namestr[self.ldst] + def str2name(self, n): + self.ldst = self.namestr.index(n) + + @classmethod + def check_opts(cls, rest): + found = False + for t in cls.typestr: + if rest.startswith(t): + found = True + rest = rest[len(t):] + if not found: + return False + #XXX check diff with hdreg TODO + return True + + def args2str(self): + args = [] + args.append(reg2str(self.rd)) + o = [] + o.append('[') + o.append(reg2str(self.rn)) + if not self.ppndx: + o.append(']') + if not self.updown: + o.append("-") + o.append(reg2str(self.rm)) + if self.ppndx: + o.append(']') + + args.append(o) + return args + + def __str__(self): + name = self.getname() + #XXX XXX swp?? + name += self.typestr[self.sh] + args = self.args2str() + args = args2str(args) + wb = ['', '!'][self.wback==1] + return name+' '+args+wb + + def breakflow(self): + if self.ldst == 0 or self.rd!=15: + return False + #XXX pc pp incremented + return True + def splitflow(self): + if self.ldst == 0 or self.rd!=15: + return False + #XXX pc pp incremented + return self.cond != COND_AL + def dstflow(self): + return True + + +class arm_hdtimm(arm_mn): + mask_list = [bm_int000, bm_ppndx, bm_updown, bm_int1, bm_wback, bm_ldst, bm_rn, bm_rd, bm_hdoff1, bm_int1, bm_sh, bm_int1, bm_hdoff2] + #and XXX str cant be SB nor SH + mask = {24:bmi_intX00X} + + typestr = ["XXX", "H", "SB", "SH"] + namestr = ['STR', 'LDR'] + def name2str(self): + return self.namestr[self.ldst] + def str2name(self, n): + self.ldst = self.namestr.index(n) + + @classmethod + def check_opts(cls, rest): + found = False + for t in cls.typestr: + if rest.startswith(t): + found = True + rest = rest[len(t):] + if not found: + return False + #XXX check diff with hdreg TODO + return True + + def args2str(self): + args = [] + args.append(reg2str(self.rd)) + o = [] + o.append('[') + o.append(reg2str(self.rn)) + if not self.ppndx: + o.append(']') + imm = [-1, 1][self.updown==1]*((self.hdoff1<<4)+self.hdoff2) + o.append(imm2str(imm)) + if self.ppndx: + o.append(']') + + args.append(o) + return args + + + def __str__(self): + name = self.getname() + #XXX XXX swp?? + name += self.typestr[self.sh] + args = self.args2str() + args = args2str(args) + wb = ['', '!'][self.wback==1] + + return name+' '+args+wb + + + def breakflow(self): + if self.ldst == 0 or self.rd!=15: + return False + #XXX pc pp incremented + return True + def splitflow(self): + if self.ldst == 0 or self.rd!=15: + return False + #XXX pc pp incremented + return self.cond != COND_AL + def dstflow(self): + return True + + +class arm_sdt(arm_mn): + mask_list = [bm_int01, bm_immop, bm_ppndx, bm_updown, bm_size, bm_wback, bm_ldst, bm_rn, bm_rd, bm_opoff] + #cannot shift amount with immop + mask = {25:bmi_int1XXXX1} + + namestr = ['STR', 'LDR'] + def name2str(self): + return self.namestr[self.ldst] + def str2name(self, n): + self.ldst = self.namestr.index(n) + + allshifts = ['LSL', 'LSR', 'ASR', 'ROR'] + + @classmethod + def check_opts(cls, rest): + if not rest: + return True + if rest[0] == "B": + rest = rest[1:] + if not rest: + return True + if rest[0] == "T": + rest = rest[1:] + if rest: + return False + return True + + def args2str(self): + args = [] + args.append(reg2str(self.rd)) + o = [] + o.append('[') + o.append(reg2str(self.rn)) + if not self.ppndx: + o.append(']') + + if self.immop: + if not self.updown: + o.append("-") + o.append([reg2str(self.rm), self.allshifts[self.shiftt], imm2str(self.amount)]) + else: + imm = [-1, 1][self.updown==1]*self.imm + o.append(imm2str(imm)) + if self.ppndx: + o.append(']') + args.append(o) + return args + + + def __str__(self): + name = self.getname() + name+=self.size2str() + #XXX TODO T bit??? name+=['', 'T'][self.wback==1] + wb = ['', '!'][self.wback==1] + args = self.args2str() + args = args2str(args) + return name+' '+args+wb + + def parse_opts(self, opts): + self.wback = 0 + self.size = 0 + if not opts: + return + if opts[0] == "B": + self.size = 1 + + def parse_args(self, args): + self.rd = str2reg(args.pop()) + + if len(args)!=1: + raise ValueError("zarb arg3", args) + args = args.pop() + args = args[::-1] + p1 = args.pop() + self.rn = str2reg(args.pop()) + + param = [] + if args[-1] == ']': + self.ppndx = 0 + param = args[:-1] + args = [] + else: + self.ppndx = 1 + param = args[args.index(']')+1:] + args = args[:args.index(']')] + + self.updown = 1 + tmp = param.pop() + if tmp =='-': + self.updown = 0 + tmp = param.pop() + + if is_imm(tmp): + self.immop = 0 + self.imm = str2imm(tmp) + else: + self.immop = 1 + self.rm = str2reg(tmp) + self.shiftt = self.allshifts.index(param.pop()) + tmp = param.pop() + if not is_imm(tmp): + raise ValueError('amount must be int') + self.amount = str2imm(tmp) + + if args: + tmp = args.pop() + if tmp!= '!': + raise "arg zarb %s"%str(tmp) + self.wback = 1 + if args: + raise ValueError('rest args...'%str(param)) + + + def breakflow(self): + if self.ldst == 0 or self.rd!=15: + return False + #XXX pc pp incremented + return True + def splitflow(self): + if self.ldst == 0 or self.rd!=15: + return False + #XXX pc pp incremented + return self.cond != COND_AL + def dstflow(self): + return False + def getdstflow(self): + return [] + def setdstflow(self, dst): + if len(dst)==0: + return + if len(dst)!=1: + raise ValueError('should be 1 dst') + def is_subcall(self): + return False + +class arm_undef(arm_mn): + mask_list = [bm_int011, bm_undef1, bm_int1, bm_undef2] + + namestr = ["UNDEF"] + def name2str(self): + return self.namestr[0] + + def args2str(self): + args = [] + args.append(imm2str(self.undef1)) + args.append(imm2str(self.undef2)) + return args + + def __str__(self): + name = self.getname() + args = self.args2str() + args = args2str(args) + + return name+' '+args + + def parse_args(self, args): + self.undef1 = str2imm(args.pop()) + self.undef2 = str2imm(args.pop()) + +class arm_bdt(arm_mn): + mask_list = [bm_int100, bm_ppndx, bm_updown, bm_psr, bm_wback, bm_ldst, bm_rn, bm_reglist] + + ad_mode_nostack = ['DA', 'DB', 'IA', 'IB'] + ad_mode_stack = ['FA', 'EA', 'FD', 'ED'] + + namestr = ['STM', 'LDM'] + def name2str(self): + return self.namestr[self.ldst] + def str2name(self, n): + self.ldst = self.namestr.index(n) + + @classmethod + def check_opts(cls, rest): + for m in cls.ad_mode_stack+cls.ad_mode_nostack: + if rest.startswith(m): + rest = rest[len(m):] + break + if rest: + return False + return True + + def args2str(self): + args = [] + args.append(reg2str(self.rn)) + if self.wback: + args.append('!') + args+=[reg2str(r) for r in self.reglist] + if self.psr: + args.append('^') + return args + + def __str__(self): + name = self.getname() + tmp = (self.ppndx<<1)+self.updown + if self.ldst!=0: + tmp = 3-tmp + if self.rn == 13: + ad_mode = self.ad_mode_stack[tmp] + else: + ad_mode = self.ad_mode_nostack[tmp] + + name+=ad_mode + args = [] + wb = ['', '!'][self.wback] + psr = ['', '^'][self.psr] + args.append(reg2str(self.rn)+wb) + args.append(reglist2str(self.reglist)) + return name+" "+", ".join(args)+psr + + def parse_opts(self, opts): + if opts in self.ad_mode_stack: + self.stackattr = True + self.bits = self.ad_mode_stack.index(opts) + elif opts in self.ad_mode_nostack: + self.stackattr = False + self.bits = self.ad_mode_nostack.index(opts) + else: + raise ValueError('opt zarb %s'%str(opts)) + + + def parse_args(self, args): + self.wback = 0 + a = args.pop() + if len(a) >1: + w = a.pop() + if w == "!": + self.wback = 1 + else: + raise ValueError('zarb arg 4', (args, a, w)) + + + self.rn = str2reg(a.pop()) + if self.stackattr != (self.rn==13): + raise ValueError('unmatch stack/nostack') + + if self.ldst!=0: + self.bits = 3-self.bits + + self.updown = self.bits & 1 + self.ppndx = self.bits >> 1 + + if len(args) !=1: + raise ValueError('zarb arg 4', args) + args = args.pop() + args = args[::-1] + self.reglist = str2reglist(args) + + self.psr = 0 + if args: + tmp = args.pop() + if tmp == '^': + self.psr = 1 + else: + raise ValueError('zarb last arg %s'%str(tmp)) + + def breakflow(self): + if self.ldst == 0 or not 15 in self.reglist: + return False + #XXX pc pp incremented + return True + def splitflow(self): + if self.ldst == 0 or not 15 in self.reglist: + return False + #XXX pc pp incremented + return self.cond != COND_AL + def dstflow(self): + return False + +class arm_br(arm_mn): + mask_list = [bm_int101, bm_lnk, bm_offs] + + namestr = ["B", "BL"] + def name2str(self): + return self.namestr[self.lnk] + def str2name(self, n): + self.lnk = self.namestr.index(n) + + @classmethod + def check_mnemo(self, mnemo): + if not mnemo.startswith('B'): + return False + l = len(mnemo) + if l==1 and mnemo in ['B']: + return True + elif l in [2,4] and mnemo.startswith('BL'): + return True + elif l == 3 and mnemo[1:] in bm_cond.n: + return True + return False + + def parse_name_cond(self, mnemo): + name, cond = None, None + if not mnemo.startswith('B'): + raise ValueError('zarb mnemo %s'%str(mnemo)) + l = len(mnemo) + if l in [1,3]: + n = mnemo[:1] + elif l in [2,4]: + n = mnemo[:2] + else: + raise ValueError('zarb mnemo %s'%str(mnemo)) + name = n + rest = mnemo[len(n):] + for i, c in enumerate(bm_cond.n): + if rest.startswith(c): + cond = i + break + if cond == None: + cond = COND_AL #default cond is AL + else: + rest = rest[len(c):] + return name, cond, rest + + def args2str(self): + if type(self.offs) in [int, long]: + args = [imm2str(self.offs)] + else: + args = [self.offs] + return args + + def __str__(self): + name = self.getname() + args = self.args2str() + args = args2str(args) + return name+' '+args + + def parse_args(self, args): + ad = args.pop() + if is_imm(ad): + self.offs = str2imm(ad) + else: + self.offs = {x86_afs.symb:{ad[0]:1}} + def breakflow(self): + return True + def splitflow(self): + return self.cond != COND_AL or self.lnk + def dstflow(self): + return True + + def getdstflow(self): + if type(self.offs) in [int, long]: + dst = (self.offset+8+self.offs)&0xFFFFFFFF + else: + dst = self.arg[0] + return [dst] + + def setdstflow(self, dst): + if len(dst)==0: + return + if len(dst)!=1: + raise ValueError('should be 1 dst') + l = dst[0] + #patch only known symbols + if l.offset !=None: + self.offs = l + def is_subcall(self): + return self.lnk + + def fixdst(self, lbls, my_offset, is_mem): + l = self.offs[x86_afs.symb].keys()[0] + offset = lbls[l] + if is_mem: + arg = {x86_afs.ad:is_mem, x86_afs.imm:offset} + else: + arg = {x86_afs.imm:offset-(my_offset)} + + self.arg = [arg] + self.offs = lbls[l]-my_offset-4 + +class arm_codt(arm_mn): + mask_list = [bm_int110, bm_ppndx, bm_updown, bm_tlen, bm_wback, bm_ldst, bm_rn, bm_crd, bm_cpnum, bm_cooff] + + namestr = ['STC', 'LDC'] + def name2str(self): + return self.namestr[self.ldst] + def str2name(self, n): + self.ldst = self.namestr.index(n) + + @classmethod + def check_opts(cls, rest): + if not rest or rest == 'L': + return True + return False + + def args2str(self): + args = [] + args.append(cop2str(self.cpnum)) + args.append(copr2str(self.crd)) + o = [] + o.append('[') + o.append(reg2str(self.rn)) + if not self.ppndx: + o.append(']') + o.append(imm2str(self.cooff)) + if self.ppndx: + o.append(']') + args.append(o) + return args + + def __str__(self): + name = self.getname() + if self.tlen: + name+='L' + args = self.args2str() + args = args2str(args) + wb = ['', '!'][self.wback] + return name+' '+args+wb + + def parse_opts(self, opts): + self.tlen = 0 + if not opts: + return + if opts =='L': + self.tlen = 1 + return + raise ValueError('opt zarb %s'%str(opts)) + + def parse_args(self, args): + self.wback = 0 + self.updown = 0 + self.cpnum = str2cop(args.pop()) + self.crd = str2copr(args.pop()) + if len(args) !=1: + raise ValueError('zarb arg 6', str(args)) + args = args.pop() + args = args[::-1] + p1 = args.pop() + self.rn = str2reg(args.pop()) + + param = [] + if args[-1] == ']': + self.ppndx = 0 + param = args[:-1] + args = [] + else: + self.ppndx = 1 + param = args[args.index(']')+1:] + args = args[:args.index(']')] + + self.updown = 1 + tmp = param.pop() + if tmp =='-': + self.updown = 0 + tmp = param.pop() + + self.cooff = str2imm(tmp) + + if args: + tmp = args.pop() + if tmp!= '!': + raise "arg zarb %s"%str(tmp) + self.wback = 1 + if args: + raise ValueError('rest args...'%str(param)) + + + +class arm_codo(arm_mn): + mask_list = [bm_int1110, bm_cpopc, bm_crn, bm_crd, bm_cpnum, bm_info, bm_int0, bm_crm] + + namestr = ["CDP"] + def name2str(self): + return self.namestr[0] + + def args2str(self): + args = [] + args.append(cop2str(self.cpnum)) + args.append(imm2str(self.cpopc)) + args.append(copr2str(self.crd)) + args.append(copr2str(self.crn)) + args.append(copr2str(self.crm)) + args.append(imm2str(self.info)) + return args + + def __str__(self): + name = self.getname() + args = self.args2str() + args = args2str(args) + return name+' '+args + + def parse_args(self, args): + self.cpnum = str2cop(args.pop()) + self.cpopc = str2imm(args.pop()) + self.crd = str2copr(args.pop()) + self.crn = str2copr(args.pop()) + self.crm = str2copr(args.pop()) + self.info = str2imm(args.pop()) + + + + +class arm_cort(arm_mn): + mask_list = [bm_int1110, bm_opmode, bm_ldst, bm_crn, bm_rd, bm_cpnum, bm_info, bm_int1, bm_crm] + + namestr = ['MCR', 'MRC'] + def name2str(self): + return self.namestr[self.ldst] + def str2name(self, n): + self.ldst = self.namestr.index(n) + + def args2str(self): + args = [] + args.append(cop2str(self.cpnum)) + args.append(imm2str(self.opmode)) + args.append(reg2str(self.rd)) + args.append(copr2str(self.crn)) + args.append(copr2str(self.crm)) + args.append(imm2str(self.info)) + return args + + def __str__(self): + name = self.getname() + args = self.args2str() + args = args2str(args) + return name+' '+args + + + def parse_args(self, args): + self.cpnum = str2cop(args.pop()) + self.opmode = str2imm(args.pop()) + self.rd = str2reg(args.pop()) + self.crn = str2copr(args.pop()) + self.crm = str2copr(args.pop()) + self.info = str2imm(args.pop()) + +class arm_swi(arm_mn): + mask_list = [bm_int1111, bm_swint] + + namestr = ["SWI"] + def name2str(self): + return self.namestr[0] + + def args2str(self): + args = [imm2str(self.swint)] + return args + + def __str__(self): + name = self.getname() + args = self.args2str() + args = args2str(args) + return name+' '+args + + def parse_args(self, args): + self.swint = str2imm(args.pop()) + + def breakflow(self): + return True + def splitflow(self): + return True + def dstflow(self): + return False + + +class arm_szext(arm_mn): + mask_list = [bm_int01101, bm_opsz, bm_szext, bm_rn, bm_rd, bm_rot, bm_int00, bm_int0111, bm_rm] + #szext may not be 01 + namestr = ['SXT', 'UXT'] + szextname = ['B16', None, 'B', 'H'] + def name2str(self): + return self.namestr[self.opsz]+['A', ''][self.rn==15]+self.szextname[self.szext] + def str2name(self, n): + self.opsz = self.namestr.index(n) + + @classmethod + def check_mnemo(self, mnemo): + if len(mnemo)<3: + return False + if not mnemo[:3] in self.namestr: + return False + rest = mnemo[3:] + if rest[0] =='A': + rest = rest[1:] + found = False + for n in self.szextname: + if not n: + continue + if rest.startswith(n): + found = True + if not found: + return False + rest = rest[len(n):] + if not rest or rest in bm_cond.n: + return True + return False + + def parse_name_cond(self, mnemo): + name, szextname, cond = None, None, None + for n in self.namestr: + if mnemo.startswith(n): + name = n + break + if not name: + raise ValueError('zarb mnemo1 %s'%str(mnemo)) + rest = mnemo[len(n):] + out = [] + if rest[0] =='A': + rest = rest[1:] + out.append('A') + self.rn = 0 + else: + self.rn=15 + for i, n in enumerate(self.szextname): + if n and rest.startswith(n): + szextname = n + self.szext = i + break + if not szextname: + raise ValueError('zarb mnemo2 %s'%str(mnemo)) + rest = rest[len(n):] + + for i, c in enumerate(bm_cond.n): + if rest.startswith(c): + cond = i + break + if cond == None: + cond = COND_AL #default cond is AL + else: + rest = rest[len(c):] + if rest: + raise ValueError("rest! %s"%str(rest)) + return name, cond, rest + + def parse_opts(self, opts): + if not opts: + return + raise ValueError('opt zarb %s'%str(opts)) + + def args2str(self): + args = [] + args.append(reg2str(self.rd)) + if self.rn!=15: + args.append(reg2str(self.rn)) + args.append(reg2str(self.rm)) + return args + + def __str__(self): + name = self.getname() + args = self.args2str() + args = args2str(args) + return name+' '+args + + + def parse_args(self, args): + + self.rd = str2reg(args.pop()) + if self.rn!=15: + self.rn = str2reg(args.pop()) + self.rm = str2reg(args.pop()) + self.rot = 0 + + + + +if __name__ == "__main__": + + import struct diff --git a/miasm/arch/arm_sem.py b/miasm/arch/arm_sem.py new file mode 100644 index 00000000..c60b9cd0 --- /dev/null +++ b/miasm/arch/arm_sem.py @@ -0,0 +1,621 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from miasm.expression.expression import * +from miasm.arch.arm_arch import * +from miasm.core.asmbloc import * + + +reg_r0 = 'R0' +reg_r1 = 'R1' +reg_r2 = 'R2' +reg_r3 = 'R3' +reg_r4 = 'R4' +reg_r5 = 'R5' +reg_r6 = 'R6' +reg_r7 = 'R7' +reg_r8 = 'R8' +reg_r9 = 'R9' +reg_r10 = 'R10' +reg_r11 = 'R11' +reg_r12 = 'R12' +reg_sp = 'SP' +reg_lr = 'LR' +reg_pc = 'PC' + +reg_zf = 'zf' +reg_nf = 'nf' +reg_of = 'of' +reg_cf = 'cf' + +zf = ExprId(reg_zf, size=1) +nf = ExprId(reg_nf, size=1) +of = ExprId(reg_of, size=1) +cf = ExprId(reg_cf, size=1) + +R0 = ExprId(reg_r0) +R1 = ExprId(reg_r1) +R2 = ExprId(reg_r2) +R3 = ExprId(reg_r3) +R4 = ExprId(reg_r4) +R5 = ExprId(reg_r5) +R6 = ExprId(reg_r6) +R7 = ExprId(reg_r7) +R8 = ExprId(reg_r8) +R9 = ExprId(reg_r9) +R10 = ExprId(reg_r10) +R11 = ExprId(reg_r11) +R12 = ExprId(reg_r12) +SP = ExprId(reg_sp) +LR = ExprId(reg_lr) +PC = ExprId(reg_pc) + + +all_registers = [ + R0, + R1, + R2, + R3, + R4, + R5, + R6, + R7, + R8, + R9, + R10, + R11, + R12, + SP, + LR, + PC, + ] + +tab_intsize = {8:int8, + 16:int16, + 32:int32, + 64:int64 + } +tab_uintsize ={8:uint8, + 16:uint16, + 32:uint32, + 64:uint64 + } + +str2regid = dict([(x.name,x) for x in all_registers]) + + + + +def get_op_msb(a): + cast_int = tab_uintsize[a.get_size()] + return ExprOp('==', ExprInt(cast_int(1)), ExprOp('>>', a, ExprInt(cast_int(a.get_size()-1)))) + + +def update_flag_zf(a): + cast_int = tab_uintsize[a.get_size()] + return [ExprAff(zf, ExprOp('==', a, ExprInt(cast_int(0))))] + +def update_flag_nf(a): + return [ExprAff(nf, ExprOp('&', get_op_msb(a), ExprInt(tab_uintsize[a.get_size()](1))))] + + +def update_flag_zn(a): + e = [] + e+=update_flag_zf(a) + e+=update_flag_nf(a) + return e + +def update_flag_logic(a): + e = [] + e+=update_flag_zn(a) + e.append(ExprAff(of, ExprInt(uint32(0)))) + e.append(ExprAff(cf, ExprInt(uint32(0)))) + return e + +def update_flag_arith(a): + e = [] + e+=update_flag_zn(a) + return e + +def check_ops_msb(a, b, c): + if not a or not b or not c or a!=b or a!=c: + raise 'bad ops size %s %s %s'%(str(a), str(b), str(c)) + +def arith_flag(a, b, c): + a_s, b_s, c_s = a.get_size(), b.get_size(), c.get_size() + check_ops_msb(a_s, b_s, c_s) + a_s, b_s, c_s = get_op_msb(a), get_op_msb(b), get_op_msb(c) + return a_s, b_s, c_s + +#z = x+y (+cf?) +def update_flag_add(x, y, z): + a, b, c = arith_flag(x, y, z) + cast_int = tab_uintsize[z.get_size()] + e = [] + e.append(update_flag_add_cf(cast_int, a, b, c)) + e.append(update_flag_add_of(cast_int, a, b, c)) + return e + +#z = x-y (+cf?) +def update_flag_sub(x, y, z): + a, b, c = arith_flag(x, y, z) + cast_int = tab_uintsize[z.get_size()] + e = [] + e.append(update_flag_sub_cf(cast_int, a, b, c)) + e.append(update_flag_sub_of(cast_int, a, b, c)) + return e + +def update_flag_sub_cf(cast_int, a, b, c): + return ExprAff(cf, ExprOp('|', + ExprOp('&', ExprOp('==', a, ExprInt(cast_int(0))), b), + ExprOp('&', c, ExprOp('|', ExprOp('==', a, ExprInt(cast_int(0))), b) + ) + ) + ) + + +def update_flag_sub_of(cast_int, a, b, c): + return ExprAff(of, ExprOp('|', + ExprOp('&', + ExprOp('==', c, ExprInt(cast_int(1))), + ExprOp('&', ExprOp('==', a, ExprInt(cast_int(0))), b) + ), + ExprOp('&', + ExprOp('==', c, ExprInt(cast_int(0))), + ExprOp('&', a, ExprOp('==', b, ExprInt(cast_int(0)))) + ) + ) + ) + + + + +def get_cf_shifter(a): + e = [] + if not isinstance(a, ExprOp): + return e + if not a.op in ['<<', '>>', 'a>>', '>>>']: + return e + #int shift amount + shifter = a.args[1] + source = a.args[0] + if isinstance(shifter, ExprInt) and shifter.arg == 0: + if a.op == '<<': + #cf is old cf + return e + elif a.op in ['>>', 'a>>']: + e.append(ExprAff(cf, get_op_msb(source))) + return e + elif a.op == '>>>': + new_cf = ExprOp('&', + ExprInt(cast_int(1)), + source + ) + e.append(ExprAff(cf, new_cf)) + return e + raise ValueError('bad op') + + + if a.op == '<<': + new_cf = ExprOp('&', + ExprInt(uint32(1)), + ExprOp('>>', + source, + ExprOp('-', + ExprInt(uint32(source.get_size())), + shifter + ) + + ) + ) + + elif a.op in ['>>', 'a>>']: + new_cf = ExprOp('&', + ExprInt(uint32(1)), + ExprOp(a.op, + source, + ExprOp('-', + shifter, + ExprInt(uint32(1)) + ) + + ) + ) + elif a.op == '>>>': + c = ExprOp('>>>', source, shifter) + new_cf = get_op_msb(c) + + if isinstance(shifter, ExprInt): + e.append(ExprAff(cf, new_cf)) + else: + e.append(ExprAff(cf, ExprCond(shifter, + new_cf, + cf)) + ) + return e + + + + +def add(x, a, b): + e = [] + c = ExprOp('+', a, b) + e.append(ExprAff(x, c)) + return e + +def adds(x, a, b): + e = [] + c = ExprOp('+', a, b) + e+=update_flag_arith(c) + e+=update_flag_add(a, b, c) + e.append(ExprAff(x, c)) + return e + +def sub(x, a, b): + e = [] + c = ExprOp('-', a, b) + e.append(ExprAff(x, c)) + return e + +def subs(x, a, b): + e = [] + c = ExprOp('-', a, b) + e+=update_flag_arith(c) + e+=update_flag_sub(a, b, c) + e.append(ExprAff(x, c)) + return e + +def eor(x, a, b): + e= [] + c = ExprOp('^', a, b) + e.append(ExprAff(x, c)) + return e + +def eors(x, a, b): + e= [] + c = ExprOp('^', a, b) + e+=update_flag_logic(c) + e.append(ExprAff(x, c)) + return e + +def l_and(x, a, b): + e= [] + c = ExprOp('&', a, b) + e.append(ExprAff(x, c)) + return e + +def l_ands(x, a, b): + e= [] + c = ExprOp('&', a, b) + e+=update_flag_logic(c) + e.append(ExprAff(x, c)) + return e + +def rsb(x, a, b): + return sub(x, b, a) + +def rsbs(x, a, b): + return subs(x, b, a) + +def adc(x, a, b): + e= [] + c = ExprOp('+', a, ExprOp('+', b, ExprCompose([ExprSliceTo(ExprInt(uint32(0)), 1, a.get_size()), ExprSliceTo(cf, 0, 1)]))) + e.append(ExprAff(x, c)) + return e + +def adcs(x, a, b): + e= [] + c = ExprOp('+', a, ExprOp('+', b, ExprCompose([ExprSliceTo(ExprInt(uint32(0)), 1, a.get_size()), ExprSliceTo(cf, 0, 1)]))) + e+=update_flag_arith(c) + e+=update_flag_add(a, b, c) + e.append(ExprAff(x, c)) + return e + +def sbc(x, a, b): + e= [] + c = ExprOp('-', + ExprOp('+', a, ExprCompose([ExprSliceTo(ExprInt(uint32(0)), 1, a.get_size()), ExprSliceTo(cf, 0, 1)])), + ExprOp('+', b, ExprInt(uint32(1))) + ) + e.append(ExprAff(x, c)) + return e + +def sbcs(x, a, b): + e= [] + c = ExprOp('-', + ExprOp('+', a, ExprCompose([ExprSliceTo(ExprInt(uint32(0)), 1, a.get_size()), ExprSliceTo(cf, 0, 1)])), + ExprOp('+', b, ExprInt(uint32(1))) + ) + e+=update_flag_arith(c) + e+=update_flag_sub(a, b, c) + e.append(ExprAff(x, c)) + return e + +def rsc(x, a, b): + return sbc(x, b, a) + +def rscs(x, a, b): + return sbcs(x, b, a) + +def tst(a, b): + e= [] + c = ExprOp('&', a, b) + e+=update_flag_logic(c) + return e + +def teq(a, b): + e= [] + c = ExprOp('^', a, b) + e+=update_flag_logic(c) + return e + +def l_cmp(a, b): + e= [] + c = ExprOp('-', a, b) + e+=update_flag_arith(c) + e+=update_flag_sub(a, b, c) + return e + +def cmn(a, b): + e= [] + c = ExprOp('+', a, b) + e+=update_flag_arith(c) + e+=update_flag_sub(a, b, c) + return e + +def orr(x, a, b): + e= [] + c = ExprOp('|', a, b) + e.append(ExprAff(x, c)) + return e + +def orrs(x, a, b): + e= [] + c = ExprOp('|', a, b) + e+=update_flag_logic(c) + e.append(ExprAff(x, c)) + return e + +def mov(x, a): + return [ExprAff(x, a)] + +def bic(x, a, b): + e= [] + c = ExprOp('&', a, ExprOp('^', b, ExprInt(uint32(0xFFFFFFFF)))) + e.append(ExprAff(x, c)) + return e + +def bics(x, a, b): + e= [] + c = ExprOp('&', a, ExprOp('^', b, ExprInt(uint32(0xFFFFFFFF)))) + e+=update_flag_logic(c) + e.append(ExprAff(x, c)) + return e + + +def mla(x, a, b, c): + e = [] + d = ExprOp('+', + ExprOp('*', a, b), + c) + e.append(ExprAff(x, d)) + + +def mlas(x, a, b, c): + e = [] + d = ExprOp('+', + ExprOp('*', a, b), + c) + e+=update_flag_zn(d) + e.append(ExprAff(x, d)) + + +def mul(x, a, b): + e = [] + c = ExprOp('*', a, b) + e.append(ExprAff(x, c)) + + + +def muls(x, a, b): + e = [] + c = ExprOp('*', a, b) + e+=update_flag_zn(c) + e.append(ExprAff(x, c)) + + +def branch(my_eip, a): + e = [] + e.append(ExprAff(PC, a)) + return e + + + +def branchl(my_eip, a): + e = [] + l = ExprOp('+', + my_eip, + ExprInt(uint32(4)), + ) + e.append(ExprAff(PC, a)) + e.append(ExprAff(LR, l)) + return e + +mnemo_func = {'add': add, + 'adds': adds, + 'sub':sub, + 'subs':subs, + 'eor':eor, + 'eors':eors, + 'and':l_and, + 'ands':l_ands, + 'rsb':rsb, + 'rsbs':rsbs, + 'adc':adc, + 'adcs':adcs, + 'sbc':sbc, + 'sbcs':sbcs, + 'rsc':rsc, + 'rscs':rscs, + 'tst':tst, + 'tsts':tst, + 'teq':teq, + 'teqs':teq, + 'cmp':l_cmp, + 'cmps':l_cmp, + 'cmn':cmn, + 'cmns':cmn, + 'orr':orr, + 'orrs':orrs, + 'mov':mov, + 'movs':mov, + 'bic':bic, + 'bics':bics, + 'b':branch, + 'bl':branchl, + } + + + +shifts2op = {'LSL':'<<', 'LSR':'>>', 'ASR':'a>>', 'ROR':'>>>', '-':'-'} + +def condition_expr(cond, exprs): + if cond == COND_AL: + return exprs + + tab_cond = {COND_EQ:zf, + COND_NE:ExprOp('==', zf, ExprInt(uint32(0))), + COND_CS:cf, + COND_CC:ExprOp('==', cf, ExprInt(uint32(0))), + COND_MI:nf, + COND_PL:ExprOp('==', nf, ExprInt(uint32(0))), + COND_VS:of, + COND_VC:ExprOp('==', of, ExprInt(uint32(0))), + COND_HI:ExprOp('&', cf, ExprOp('==', zf, ExprInt(uint32(0)))), + COND_LS:ExprOp('&', zf, ExprOp('==', cf, ExprInt(uint32(0)))), + COND_GE:ExprOp('==', nf, of), + COND_LT:ExprOp('^', nf, of), + COND_GT:ExprOp('|', + ExprOp('&', + ExprOp('==', zf, ExprInt(uint32(0))), + ExprOp('|',nf, of) + ), + ExprOp('&', + ExprOp('==', nf, ExprInt(uint32(0))), + ExprOp('==', of, ExprInt(uint32(0))) + ) + ), + COND_LE:ExprOp('|', + zf, + ExprOp('^', nf, of) + ), + } + if not cond in tab_cond: + raise 'unknown cond' + cond = tab_cond[cond] + out = [] + for e in exprs: + src, dst = e.src, e.dst + out.append(ExprAff(dst, ExprCond(cond, src, dst))) + return out + + +def get_instr_expr_args(mn, args, my_eip): + print args + wback = False + outa = [] + optmem = lambda x:x + for a in args: + l = len(a) + if type(a) is str and a in str2regid: + outa.append(str2regid[a]) + continue + elif type(a) is str and is_imm(a): + outa.append(ExprInt(uint32(str2imm(a)))) + continue + elif type(a) is str and a == '!': + wback = True + continue + elif not type(a) == list: + print 'spot symb', a + break + if a[0] == '[' and a[-1] == ']': + optmem = ExprMem + a = a[1:-1] + l-=2 + + + print a + t = None + a.reverse() + u = a.pop() + if not u in str2regid: + raise ValueError('unknown1 arg', str(a)) + u1 = str2regid[u] + if len(a) >1: + u = a.pop() + if not u in shifts2op: + raise ValueError('unknown2 arg', str(a)) + t = shifts2op[u] + + if len(a)>0: + u = a.pop() + print u + if is_imm(u): + u2 = ExprInt(uint32(str2imm(u))) + elif u in str2regid: + u2 = str2regid[u] + else: + raise ValueError('unknown3 arg', str(a)) + if l==1: + o = u1 + elif l == 2: + o = ExprOp('+', u1, u2) + elif l == 3: + o = ExprOp(t, u1, u2) + else: + rezrezrezr + o = optmem(o) + outa.append(o) + print args + print [str(x) for x in outa] + n = mn.name2str() + + exprs = [] + if isinstance(mn, arm_data): + if n in ['mov', 'eor', 'and', 'tst', 'teq', 'cmp', 'orr', 'bic']: + exprs += get_cf_shifter(outa[-1]) + n+=mn.scc2str() + elif isinstance(mn, arm_br): + d = mn.getdstflow() + if len(d) !=1: + raise ValueError("zarb dst", d) + + outa = [my_eip, ExprInt(uint32(d[0].offset))] + else: + print 'unimpl mnemo', str(n) + return None + + + print 'ARGS', [str(x) for x in outa] + print n, args + exprs += mnemo_func[n.lower()](*outa) + + exprs = condition_expr(mn.cond, exprs) + print 'EXPR', [str(x) for x in exprs] + return exprs + diff --git a/miasm/arch/ia32_arch.py b/miasm/arch/ia32_arch.py new file mode 100644 index 00000000..5cb2a3ec --- /dev/null +++ b/miasm/arch/ia32_arch.py @@ -0,0 +1,2223 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from numpy import uint8, uint16, uint32, uint64, int8, int16, int32, int64 +import struct +import logging +from miasm.core.parse_ad import parse_ad, ad_to_generic +from miasm.arch.ia32_reg import x86_afs +import shlex + + +log = logging.getLogger("x86escape") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.WARN) + + +tab_int_size = {int8:8, + uint8:8, + int16:16, + uint16:16, + int32:32, + uint32:32, + int64:64, + uint64:64 + } + +tab_size2int = {x86_afs.u08:uint8, + x86_afs.u16:uint16, + x86_afs.u32:uint32, + x86_afs.s08:int8, + x86_afs.s16:int16, + x86_afs.s32:int32} + + + + + +prefix_dic = {"lock":0xF0, "repnz":0xF2, "repne":0xF2, "repz":0xF3, "repe":0xF3, "rep":0xF3, } + +prefix_dic_inv = dict(map(lambda x:(x[1],x[0]), prefix_dic.items())) + +#'es'|'cs'|'ss'|'ds'|'fs'|'gs') ':' ''' +prefix_seg = {0:0x26, 1:0x2E, 2:0x36, 3:0x3E, 4:0x64, 5:0x65} + +prefix_seg_inv = dict(map(lambda x:(x[1],x[0]), prefix_seg.items())) + +class mnemonic: + def __init__(self, name, opc, afs, rm, modifs, modifs_orig, sem): + self.name = name + self.opc = opc + + self.afs = afs + self.rm = rm + + self.modifs = modifs + self.modifs_orig = modifs_orig + + def __str__(self): + return self.name+' '+str(self.opc)+' '+str(self.afs)+' '+str(self.rm)+' '+str(self.modifs)+' '+str(self.modifs_orig)#+' '+str(self.sem)+' ' + + +def mask_opc_to_i(mask, opc): + log.debug("mask %x opc %x"%(mask, opc)) + return [i for i in range(0x100) if (i & mask) == opc] + +mask_d = 0x38 +mask_reg = 0xF8 +mask_cond = 0xF0 + +d0 = 0<<3 +d1 = 1<<3 +d2 = 2<<3 +d3 = 3<<3 +d4 = 4<<3 +d5 = 5<<3 +d6 = 6<<3 +d7 = 7<<3 +reg = "reg" +noafs = "noafs" +cond = "cond" +cond_list = ["o", + "no", + "b", + "ae", + "e", + "nz", + "be", + "a", + "s", + "ns", + "p", + "np", + "l",# "nge", + "ge", + "le", + "g" + ] +no_rm = [] +rmr = "rmr" + +imm = x86_afs.imm +ims = x86_afs.ims +mim = x86_afs.mim +u08 = x86_afs.u08 +s08 = x86_afs.s08 +u16 = x86_afs.u16 +s16 = x86_afs.s16 +u32 = x86_afs.u32 +s32 = x86_afs.s32 +im1 = x86_afs.im1 +im3 = x86_afs.im3 + +r_eax = {x86_afs.r_eax:1, x86_afs.ad:False} +r_cl = {x86_afs.reg_list8.index(x86_afs.r_cl):1, x86_afs.ad:False, x86_afs.size:x86_afs.u08} +r_dx = {x86_afs.reg_list16.index(x86_afs.r_dx):1, x86_afs.ad:False, x86_afs.size:x86_afs.u16} + + +w8 = "w8" +se = "se" +sw = "sw" +ww = "ww" +sg = "sg" +dr = "dr" +cr = "cr" +ft = "ft" +w64= "w64" +sd = "sd" #single/double +wd = "wd" #word/dword + + +bkf = "breakflow" +spf = "splitflow" +dtf = "dstflow" + +seip = "seip" #seteip +stpeip = "stpeip" #stop eip + +unsanity_mnemo = ['nop', 'monitor', 'mwait', 'fadd', 'faddp', 'fiadd', 'fcmovb', 'fcom', 'fcomp', 'fcomip', + 'fdiv', 'fdivr', 'fidivr', 'fdivrp', 'ficom', 'ficomp', 'fild', 'fist', 'fistp', 'fisttp', + 'fld', 'fldcw', 'fld1', 'fldl2t', "fldl2e", "fldpi", "fldlg2", "fldln2", "fldz", 'fldenv', 'fmul', 'fimul', 'fmulp', 'fst', 'fstp', 'fnstcw', 'fnstenv', + 'fnstsw', 'fsub', 'fsubr', 'fisubr', 'fsubrp', 'ftst', 'fucom', 'fucompp', 'fxam', 'fxtract', 'fyl2x', 'fyl2xp1', 'fsqrt', 'fsincos', 'fsin', 'fscale', + 'fcos', 'fdecstp', 'fnop', 'fpatan', 'fprem', 'fprem1', 'fptan', 'frndint', "shl", 'sal', 'sar'] + + +mask_drcrsg = {cr:0x100, dr:0x200, sg:0x400} + +def hexdump(a): + return reduce(lambda x,y:x+"%.2X"%ord(y), a, "") + +def is_address(a): + if x86_afs.ad in a and a[x86_afs.ad]: + return True + return False + +def is_imm(a): + if x86_afs.ad in a and a[x86_afs.ad]: + return False + if not (x86_afs.imm in a or x86_afs.symb in a) : + return False + for k in a: + if not k in [x86_afs.imm, x86_afs.size, x86_afs.ad, x86_afs.symb]: + return False + return True + +def is_ad_lookup(a): + if not x86_afs.ad in a or not a[x86_afs.ad]: + return False + if not (x86_afs.imm in a or x86_afs.symb in a) : + return False + for k in a: + if not k in [x86_afs.imm, x86_afs.size, x86_afs.ad, x86_afs.symb]: + return False + return True + +def is_reg(a): + if x86_afs.ad in a and a[x86_afs.ad]: + return False + if x86_afs.imm in a: + return False + if x86_afs.symb in a: + return False + + return True + +def get_label(a): + if x86_afs.ad in a: + return None + if x86_afs.imm in a: + return None + if not x86_afs.symb in a: + return None + n = a[x86_afs.symb] + if len(n)!=1: + return None + k = n.keys()[0] + if n[k] != 1: + return None + return k + + + +def check_imm_size(imm, size): + i = int32(uint32(imm)) + if not size in [u08, s08, u16, s16, u32, s32]: + raise ValueError("unknown size %s"%size) + if size == u08 and imm >= 0 and imm < 0x100: + return uint8(imm) + elif size == s08 and i >=-0x80 and i < 0x80: + return int8(i) + elif size == u16 and imm >= 0 and imm < 0x10000: + return uint16(imm) + elif size == s16 and i >=-0x8000 and i < 0x8000: + return int16(i) + elif size == u32 and imm >=-0x100000000L and imm < 0x100000000L: + return uint32(imm) + elif size == s32 and i >=-0x80000000 and i < 0x80000000: + return int32(i) + return None + + +def dict_to_ad(d, modifs = {}, mnemo_mode = u32): + size = [x86_afs.u32, x86_afs.u08][modifs[w8]==True] + #overwrite w8 + if modifs[sd]!=None: + size = [x86_afs.f32, x86_afs.f64][modifs[sd]==True] + elif modifs[wd]: + size = x86_afs.u16 + + tab32 = {x86_afs.u08:x86_afs.reg_list8, x86_afs.u16:x86_afs.reg_list16, x86_afs.u32:x86_afs.reg_list32,x86_afs.f32:x86_afs.reg_flt} + tab16 = {x86_afs.u08:x86_afs.reg_list8, x86_afs.u16:x86_afs.reg_list32, x86_afs.u32:x86_afs.reg_list16} + ad_size = {x86_afs.u08:"byte ptr", x86_afs.u16:"word ptr", x86_afs.u32:"dword ptr", x86_afs.f32:"single ptr", x86_afs.f64:"double ptr"} + + if is_reg(d): + n = [x for x in d if type(x) in [int, long]] + if len(n)!=1: + raise ValueError("bad reg! %s"%str(d)) + n = n[0] + if x86_afs.size in d and d[x86_afs.size] == x86_afs.size_seg : + t = x86_afs.reg_sg + elif x86_afs.size in d: + my_s = d[x86_afs.size] + if my_s == x86_afs.f64: + my_s = x86_afs.u32 + t = tab32[my_s] + else: + if mnemo_mode == u32: + t = tab32[size] + else: + t = tab16[size] + if modifs[dr] and n>0x7: + t = x86_afs.reg_dr + n&=7 + if modifs[cr] and n>0x7: + t = x86_afs.reg_cr + n&=7 + if modifs[sg] and n>0x7: + t = x86_afs.reg_sg + n&=7 + if modifs[sd] is not None: + t = tab32[size] + n&=7 + + try: + out = t[n] + except: + print 'WARNING!dict2ad', t, str(d) + out = "" + elif is_imm(d): + out = "" + if x86_afs.imm in d: + imm_tmp = int(d[x86_afs.imm]) &0xffffffffL + if imm_tmp<0: + out+='-0x%.8X'%-imm_tmp + else: + out+='0x%.8X'%imm_tmp + + if x86_afs.symb in d: + #XXX todo multiple ref + if out!="": out+='+' + for c in d[x86_afs.symb]: + + if d[x86_afs.symb][c]==1: + out += '%s'%str(c.name) + else: + out += '%d,%s'%(int(d[x86_afs.symb][c]), str(c)) + + elif is_address(d): + if x86_afs.size in d: + size = d[x86_afs.size] + + out = [ad_size[size]] + segment = " " + if x86_afs.segm in d: + segment += x86_afs.reg_sg[d[x86_afs.segm]]+':' + + for k in d: + if k in [x86_afs.ad, x86_afs.size, x86_afs.segm]: + continue + elif k == x86_afs.imm: + if int(d[k])<0: + out.append('-0x%.8X'%-int(d[k])) + else: + out.append('0x%.8X'%int(d[k])) + elif type(k) in [int, long]: + if d[k] ==1: + out.append(x86_afs.reg_list32[k]) + else: + out.append(str(int(d[k]))+'*'+x86_afs.reg_list32[k]) + elif k == x86_afs.symb: + out.append(str(d[k])) + else: + raise ValueError('strange ad componoant: %s'%str(d)) + out = out[0]+segment+'['+ reduce(lambda x,y: x+"+"+y, out[1:], "")[1:] + ']' + else: + raise ValueError('unknown arg %s'%str(d)) + return out + + + +class x86allmncs: + def print_op(self, optab, decal): + cpt = -1 + for i in optab: + cpt+=1 + if type(i) == list: + self.print_op(i, decal+1) + elif i == None: + pass + else: + print "%.3d "%cpt+"\t"*decal + str(i) + + + def print_tab(self): + for i in range(0x100): + if type(self.db_afs[i]) == list: + for j in range(0x100): + print "%.2X %.2X\t"%(i,j), + print self.db_afs[i][j] + else: + print "%.2X\t"%i+str(self.db_afs[i]) + + + + def get_afs(self, bin, m, size_m): + my_uint = uint32 + if size_m == u32: + db_afs = self.db_afs + else: + db_afs = self.db_afs_16 + + mod, re, rm = self.modrm(m) + if type(db_afs[m])==list: + a = dict(db_afs[m][ord(bin.readbs())]) + else: + a = dict(db_afs[m]) + if x86_afs.imm in a: + if a[x86_afs.imm] == x86_afs.u08: + a[x86_afs.imm] = my_uint(struct.unpack('B', bin.readbs())[0]) + elif a[x86_afs.imm] == x86_afs.s08: + a[x86_afs.imm] = my_uint(struct.unpack('b', bin.readbs())[0]) + elif a[x86_afs.imm] == x86_afs.u32: + a[x86_afs.imm] = my_uint(struct.unpack('I', bin.readbs(4))[0]) + elif a[x86_afs.imm] == x86_afs.u16: + a[x86_afs.imm] = my_uint(struct.unpack('H', bin.readbs(2))[0]) + else: + raise ValueError('imple other afs ... ', str(a[x86_afs.imm])) + return re, a + + def get_afs_re(self, re): + return {x86_afs.ad:False, re:1} + + + + def get_im_fmt(self, modifs, mnemo_mode, im): + if modifs[se]: + fmt,t = ('b',s08) + elif modifs[w8]: + if im == x86_afs.imm: + fmt,t = ('B',u08) + elif im == x86_afs.ims: + fmt,t = ('b',s08) + else: + raise ValueError("error encode %s"%str(im)) + else: + if im == x86_afs.imm: + if mnemo_mode == u32: fmt,t = ('I',u32) + else: fmt,t = ('H',u16) + elif im == x86_afs.ims: + if mnemo_mode == u32: fmt,t = ('i',s32) + else: fmt,t = ('h',s16) + + + return struct.calcsize(fmt), fmt,t + + def modrm(self, c): + return (c>>6)&3, (c>>3)&7, c&7 + def sib(self, c): + return self.modrm(c) + + def init_pre_modrm(self): + + self.sib_rez_u08_ebp = [{x86_afs.ad:True} for i in range(0x100)] + self.sib_rez_u32_ebp = [{x86_afs.ad:True} for i in range(0x100)] + self.sib_rez_u32 = [{x86_afs.ad:True} for i in range(0x100)] + + for sib_rez in [self.sib_rez_u08_ebp, + self.sib_rez_u32_ebp, + self.sib_rez_u32 + ]: + for index in range(0x100): + ss, i, r = self.modrm(index) + + if r == 5: + if sib_rez == self.sib_rez_u08_ebp: + sib_rez[index][x86_afs.imm] = x86_afs.s08 + sib_rez[index][x86_afs.reg_dict[x86_afs.r_ebp]] = 1 + elif sib_rez == self.sib_rez_u32_ebp: + sib_rez[index][x86_afs.imm] = x86_afs.u32 + sib_rez[index][x86_afs.reg_dict[x86_afs.r_ebp]] = 1 + elif sib_rez == self.sib_rez_u32: + sib_rez[index][x86_afs.imm] = x86_afs.u32 + else: + if sib_rez == self.sib_rez_u08_ebp: + sib_rez[index][r]=1 + sib_rez[index][x86_afs.imm] = x86_afs.s08 + elif sib_rez == self.sib_rez_u32_ebp: + sib_rez[index][r]=1 + sib_rez[index][x86_afs.imm] = x86_afs.u32 + elif sib_rez == self.sib_rez_u32: + sib_rez[index][r]=1 + + + if i == 4: + continue + + tmp = i + if tmp in sib_rez[index]: + sib_rez[index][tmp]+=[1, 2, 4, 8][ss] + else: + sib_rez[index][tmp] =[1, 2, 4, 8][ss] + + #32bit + self.db_afs = [None for i in range(0x100)] + for i in range(0x100): + index = i + mod, re, rm = self.modrm(i) + + if mod == 0: + if rm == 4: + self.db_afs[index] = self.sib_rez_u32 + elif rm == 5: + self.db_afs[index] = {x86_afs.ad:True, x86_afs.imm:x86_afs.u32} + else: + self.db_afs[index] = {x86_afs.ad:True, rm:1} + elif mod == 1: + if rm == 4: + self.db_afs[index] = self.sib_rez_u08_ebp + continue + tmp = {x86_afs.ad:True, rm:1} + if rm == 0: + tmp[x86_afs.imm] = x86_afs.s08 + else: + tmp[x86_afs.imm] = x86_afs.s08 + self.db_afs[index] = tmp + + elif mod == 2: + if rm == 4: + self.db_afs[index] = self.sib_rez_u32_ebp + else: + self.db_afs[index] = {x86_afs.ad:True, rm:1,x86_afs.imm:x86_afs.u32} + elif mod == 3: + self.db_afs[index] = {x86_afs.ad:False, rm:1} + + #16bit + self.db_afs_16 = [None for i in range(0x100)] + _si = x86_afs.reg_dict[x86_afs.r_si] + _di = x86_afs.reg_dict[x86_afs.r_di] + _bx = x86_afs.reg_dict[x86_afs.r_bx] + _bp = x86_afs.reg_dict[x86_afs.r_bp] + for i in range(0x100): + index = i + mod, re, rm = self.modrm(i) + + if mod == 0: + if rm == 4: + self.db_afs_16[index] = {x86_afs.ad:True,_si:1} + elif rm == 5: + self.db_afs_16[index] = {x86_afs.ad:True,_di:1} + elif rm == 6: + self.db_afs_16[index] = {x86_afs.ad:True,x86_afs.imm:x86_afs.u16}#{x86_afs.ad:True,_bp:1} + elif rm == 7: + self.db_afs_16[index] = {x86_afs.ad:True,_bx:1} + else: + self.db_afs_16[index] = {x86_afs.ad:True, + [_si, _di][rm%2]:1, + [_bx, _bp][(rm>>1)%2]:1} + elif mod in [1,2]: + if mod==1: + if rm==0: + my_imm=x86_afs.s08 + else: + my_imm=x86_afs.u08 + else: + my_imm=x86_afs.u16 + + if rm==4: + self.db_afs_16[index] = {x86_afs.ad:True,_si:1, x86_afs.imm:my_imm} + elif rm==5: + self.db_afs_16[index] = {x86_afs.ad:True,_di:1, x86_afs.imm:my_imm} + elif rm==6: + self.db_afs_16[index] = {x86_afs.ad:True,_bp:1, x86_afs.imm:my_imm} + elif rm==7: + self.db_afs_16[index] = {x86_afs.ad:True,_bx:1, x86_afs.imm:my_imm} + else: + self.db_afs_16[index] = {x86_afs.ad:True, + [_si, _di][rm%2]:1, + [_bx, _bp][(rm>>1)%2]:1, + x86_afs.imm:my_imm} + + elif mod == 3: + self.db_afs_16[index] = {x86_afs.ad:False, rm:1} + + + def addop(self, name, opc, afs, rm, modif_desc, prop_dict, sem): + prop_dict.update(sem) + modifs = dict([[x, True] for x in modif_desc]) + base_modif = dict([[x, None] for x in [w8, se, sw, ww, sg, dr, cr, ft, w64, sd, wd, bkf, spf, dtf]]) + base_modif.update(modifs) + + #update with forced properties + base_modif.update(prop_dict) + base_mnemo = [(opc, base_modif)] + + #XXX zarb: default se inverted? + if se in modif_desc: + tmp = base_mnemo[0][1] + tmp[se] = False + base_mnemo = [(base_mnemo[0][0], tmp)] + + log.debug(modifs) + for modif in modifs: + base_mnemo_add = [] + for opc, n_m in base_mnemo: + n_m = dict(n_m) + n_m[modif]= not n_m[modif] + + opc = opc[:] + opc[modif_desc[modif][0]] |=(1<<modif_desc[modif][1]) + + base_mnemo_add.append((opc, n_m)) + + base_mnemo+=base_mnemo_add + + for opc, n_m in base_mnemo: + #unassociable modifs XXX here cause structure generation + if n_m[se] and n_m[w8]: + continue + + if afs in [d0, d1, d2, d3, d4, d5, d6, d7]: + opc+=[afs] + mask = mask_d + elif afs in [reg]: + mask = mask_reg + elif afs == noafs: + mask = 0xFF + elif afs == cond: + mask = mask_cond + else: + raise ValueError('bug in %s %d'%(name, afs)) + + #find mnemonic table + insert_tab = self.db_mnemo + log.debug(name) + log.debug(opc ) + log.debug(mask) + for i in opc[:-1]: + if insert_tab[i] == None: + insert_tab[i] = [None for x in range(0x100)] + insert_tab = insert_tab[i] + + keys = mask_opc_to_i(mask, opc[-1]) + if afs == cond: + for k in keys: + opc_tmp = opc[:] + i_k = k&(mask_cond^0xFF) + opc_tmp[-1]|=i_k + mnemo = mnemonic(name+cond_list[i_k], opc_tmp, afs, rm, n_m, modif_desc, sem) + if insert_tab[k]!=None and not name in unsanity_mnemo: + raise ValueError("sanity check fail in mnemo affect %s"%str(insert_tab[k])) + insert_tab[k] = mnemo + #fast mnemo_lookup + if not mnemo.name in self.mnemo_lookup: + self.mnemo_lookup[mnemo.name] = [mnemo] + elif not mnemo in self.mnemo_lookup[mnemo.name]: + self.mnemo_lookup[mnemo.name].append(mnemo) + + else: + mnemo = mnemonic(name, opc, afs, rm, n_m, modif_desc, sem) + for k in keys: + if insert_tab[k]!=None and not name in unsanity_mnemo: + raise ValueError("sanity check fail in mnemo affect %s"%str(insert_tab[k])) + insert_tab[k] = mnemo + #fast mnemo_lookup + if not mnemo.name in self.mnemo_lookup: + self.mnemo_lookup[mnemo.name] = [mnemo] + elif not mnemo in self.mnemo_lookup[mnemo.name]: + self.mnemo_lookup[mnemo.name].append(mnemo) + + def find_mnemo(self, name, mnemo_list = None, candidate = None): + if name in self.mnemo_lookup.keys(): + return self.mnemo_lookup[name] + else: + return [] + + + + + + + + def get_address_afs(self, a): + l = parse_ad(a) + return ad_to_generic(l) + + def get_address_afs_hex(self, adprops): + out = [] + for ad in adprops: + candidate = [] + for i in range(0x100): + index = i&0xC7 + if type(self.db_afs[index])==list: + for j in range(0x100): + if self.db_afs[index][j] == ad: + if not (index, j) in candidate: + candidate.append((index, j) ) + + else: + if self.db_afs[index] == ad: + if not (index, None) in candidate: + candidate.append((index, None) ) + + out.append(candidate) + return out + + def forge_opc(self, out_opc, a, a2 = None): + if a2!=None : + k = [x for x in a2.keys() if type(x) in [long, int]] + if a2[x86_afs.ad] or x86_afs.imm in a2 or len(k)!=1: + raise ValueError('bad a2 forge %s'%str(a2)) + out_opc[0].append(k[0]<<3) + + #if not a[x86_afs.ad]: + del a[x86_afs.size] + + log.debug(a) + b = ad_to_generic(a) + log.debug(b) + raw = self.get_address_afs_hex(b) + + b_out = [] + raw_out = [] + for i in range(len(b)): + if not raw[i] : + continue + b_out.append(b[i]) + raw_out.append(raw[i]) + + b = b_out + raw = raw_out + out_opc_o = [] + p_val = [] + + for i in range(len(raw)): + for r in raw[i]: + out_opc_o.append(out_opc[0][:]) + out_opc_o[-1][-1]|=r[0] + if r[1]!=None: + out_opc_o[-1].append(r[1]) + log.debug( b[i]) + if x86_afs.imm in b[i]: + if x86_afs.imm in a: + v = a[x86_afs.imm] + else: + v = 0 + + v = check_imm_size(v, b[i][x86_afs.imm]) + if v == None: + log.debug("cannot encode this val in size forge!") + return None, None + + p_val.append({x86_afs.size:b[i][x86_afs.imm], x86_afs.imm:v}) + else: + p_val.append({}) + + return out_opc_o, p_val + + def check_size_modif(self, size, modifs): + if modifs[sd] is not None: + if size != [x86_afs.f32, x86_afs.f64][modifs[sd]==False]: #XXX 32 should be reg not stX??? + log.debug('checksize: not good fXX (%s)'%str(size)) + return False + else: + return True + if modifs[wd] is not None: + if size != [x86_afs.u32, x86_afs.u16][modifs[wd]]: + log.debug('checksize: not good w/dw') + return False + else: + return True + + if size != [x86_afs.u32, x86_afs.u08][modifs[w8]==True]: + log.debug('checksize: not good w8:%s'%str(size)) + return False + return True + + + def __init__(self): + + self.mnemo_lookup = {} + self.init_pre_modrm() + self.op_db = {} + + self.db_mnemo = [None for x in range(0x100)] + addop = self.addop + + + #x86 + + addop("aaa", [0x37], noafs, no_rm , {} ,{} , {}, ) + #addop("aad", [0xD5, 0x0A], noafs, no_rm , {} ,{} , {}, ) + #addop("aam", [0xD4, 0x0A], noafs, no_rm , {} ,{} , {}, ) + addop("aad", [0xD5], noafs, [u08] , {} ,{} , {}, ) + addop("aam", [0xD4], noafs, [u08] , {} ,{} , {}, ) + + addop("aas", [0x3F], noafs, no_rm , {} ,{} , {}, ) + + addop("adc", [0x14], noafs, [r_eax,imm] , {w8:(0,0)} ,{} , {}, ) + addop("adc", [0x80], d2, [imm] , {w8:(0,0),se:(0,1)},{} , {}, ) + addop("adc", [0x10], noafs, [rmr] , {w8:(0,0),sw:(0,1)},{} , {}, ) + + addop("add", [0x04], noafs, [r_eax,imm] , {w8:(0,0)} ,{} , {}, ) + addop("add", [0x80], d0, [imm] , {w8:(0,0),se:(0,1)},{} , {}, ) + addop("add", [0x00], noafs, [rmr] , {w8:(0,0),sw:(0,1)},{} , {}, ) + + addop("and", [0x24], noafs, [r_eax,imm] , {w8:(0,0)} ,{} , {}, ) + addop("and", [0x80], d4, [imm] , {w8:(0,0),se:(0,1)},{w8:True} , {}, ) + addop("and", [0x20], noafs, [rmr] , {w8:(0,0),sw:(0,1)},{} , {}, ) + + addop("arpl", [0x63], noafs, [rmr] , {} ,{sw:True,wd:True} , {}, ) + + addop("bsf", [0x0F, 0xBC], noafs, [rmr] , {} ,{} , {}, ) + addop("bsr", [0x0F, 0xBD], noafs, [rmr] , {} ,{} , {}, ) + addop("bswap", [0x0F, 0xC8], reg , no_rm , {} ,{} , {}, ) + + addop("bt", [0x0F, 0xA3], noafs, [rmr] , {} ,{sw:True} , {}, ) + addop("bt", [0x0F, 0xBA], d4 , [u08] , {} ,{} , {}, ) + addop("btc", [0x0F, 0xBB], noafs, [rmr] , {} ,{sw:True} , {}, ) + addop("btc", [0x0F, 0xBA], d7 , [u08] , {} ,{} , {}, ) + addop("btr", [0x0F, 0xB3], noafs, [rmr] , {} ,{sw:True} , {}, ) + addop("btr", [0x0F, 0xBA], d6 , [u08] , {} ,{} , {}, ) + addop("bts", [0x0F, 0xAB], noafs, [rmr] , {} ,{sw:True} , {}, ) + addop("bts", [0x0F, 0xBA], d5 , [u08] , {} ,{} , {}, ) + + addop("call", [0xE8], noafs, [s32] , {} ,{} , {bkf:True,spf:True,dtf:True}) + addop("call", [0xFF], d2 , no_rm , {} ,{} , {bkf:True,spf:True,dtf:True}) + addop("call", [0x9A], noafs, [imm,u16] , {} ,{} , {bkf:True,spf:True,dtf:True}) + addop("callf", [0xFF], d3, no_rm , {} ,{} , {bkf:True,spf:True,dtf:True}) #XXX + + addop("cbw", [0x98], noafs, [r_eax] , {} ,{} , {}, ) + addop("clc", [0xF8], noafs, no_rm , {} ,{} , {}, ) + addop("cld", [0xFC], noafs, no_rm , {} ,{} , {}, ) + addop("cli", [0xFA], noafs, no_rm , {} ,{} , {}, ) + addop("clts", [0x0F, 0x06], noafs, no_rm , {} ,{} , {}, ) + addop("cmc", [0xF5], noafs, no_rm , {} ,{} , {}, ) + + addop("cmov", [0x0F, 0x40], cond , [rmr] , {} ,{} , {}, ) + + addop("cmp", [0x3C], noafs, [r_eax,imm] , {w8:(0,0)} ,{} , {}, ) + addop("cmp", [0x80], d7, [imm] , {w8:(0,0),se:(0,1)},{} , {}, ) + addop("cmp", [0x38], noafs, [rmr] , {w8:(0,0),sw:(0,1)},{} , {}, ) + + addop("cmpsb", [0xA6], noafs, no_rm , {} ,{w8:True} , {}, ) + addop("cmpsd", [0xA7], noafs, no_rm , {} ,{w8:False} , {}, ) + + + addop("cmpxchg",[0x0F, 0xB0], noafs, [r_eax,rmr] , {w8:(1,0)} ,{} , {}, ) + addop("cmpxchg8b",[0x0F, 0xC7], d1 , no_rm , {} ,{} , {}, ) + addop("cpuid", [0x0F, 0xA2], noafs, no_rm , {} ,{} , {}, ) + + #ddop("cwd", [0x99], noafs, [r_eax] , {} ,{} , {}, ) + addop("cdq", [0x99], noafs, no_rm , {} ,{} , {}, ) + + addop("daa", [0x27], noafs, no_rm , {} ,{} , {}, ) + addop("das", [0x2F], noafs, no_rm , {} ,{} , {}, ) + addop("dec", [0x48], reg , no_rm , {} ,{} , {}, ) + addop("dec", [0xFE], d1 , no_rm , {w8:(0,0)} ,{} , {}, ) + addop("div", [0xF6], d6 , no_rm , {w8:(0,0)} ,{} , {}, ) + + addop("enter", [0xC8], noafs, [u08, u16] , {} ,{} , {}, ) + + addop("hlt", [0xF4], noafs, no_rm , {} ,{} , {bkf:True} ) + + addop("idiv", [0xF6], d7 , no_rm , {w8:(0,0)} ,{} , {}, ) + + addop("imul", [0xF6], d5 , no_rm , {w8:(0,0)} ,{} , {}, ) + addop("imul", [0x0F, 0xAF], noafs, [rmr] , {} ,{sw:False} , {}, ) + addop("imul", [0x69], noafs, [rmr, imm] , {se:(0,1)} ,{sw:False} , {}, ) + + addop("in", [0xE4], noafs, [r_eax, u08] , {w8:(0,0)} ,{} , {}, ) + addop("in", [0xEC], noafs, [r_eax,r_dx] , {w8:(0,0)} ,{} , {}, ) + + addop("inc", [0x40], reg , no_rm , {} ,{} , {}, ) + addop("inc", [0xFE], d0 , no_rm , {w8:(0,0)} ,{} , {}, ) + + addop("ins", [0x6C], noafs, no_rm , {w8:(0,0)} ,{} , {}, ) + + addop("int", [0xCC], noafs, [im3] , {} ,{} , {}, ) + addop("int", [0xCD], noafs, [u08] , {} ,{} , {}, ) + + addop("into", [0xCE], noafs, no_rm , {} ,{} , {}, ) + + addop("invd", [0x0F, 0x08], noafs, no_rm , {} ,{} , {}, ) + addop("invlpg",[0x0F, 0x01], d7 , no_rm , {} ,{} , {}, ) + + addop("iret", [0xCF], noafs, no_rm , {} ,{} , {bkf:True} ) + + addop("j", [0x70], cond , [s08] , {} ,{} , {bkf:True,spf:True,dtf:True}) + addop("j", [0x0F, 0x80], cond , [s32] , {} ,{} , {bkf:True,spf:True,dtf:True}) + addop("jecxz", [0xE3], noafs, [s08] , {} ,{} , {bkf:True,spf:True,dtf:True}) + + addop("jmp", [0xE9], noafs, [ims] , {w8:(0,1)} ,{w8:False} , {bkf:True,dtf:True} ) + addop("jmp", [0xFF], d4 , no_rm , {} ,{} , {bkf:True,dtf:True} ) + addop("jmpf", [0xFF], d5 , no_rm , {} ,{} , {bkf:True,dtf:True} ) + + addop("lahf", [0x9F], noafs, no_rm , {} ,{} , {}, ) + addop("lar", [0x0F, 0x02], noafs, no_rm , {} ,{} , {}, ) + addop("ldmxcsr",[0x0F, 0xAE], d2 , no_rm , {} ,{} , {}, ) + addop("lds", [0xC5], noafs, [rmr] , {} ,{} , {}, ) + addop("lss", [0x0F, 0xB2], noafs, [rmr] , {} ,{} , {}, ) + addop("les", [0xC4], noafs, [rmr] , {} ,{} , {}, ) + addop("lfs", [0x0F, 0xB4], noafs, [rmr] , {} ,{} , {}, ) + addop("lgs", [0x0F, 0xB5], noafs, [rmr] , {} ,{} , {}, ) + + addop("lea", [0x8D], noafs, [rmr] , {} ,{} , {}, ) + + addop("leave", [0xC9], noafs, no_rm , {} ,{} , {}, ) + addop("lfence",[0x0F, 0xAE], d5 , no_rm , {} ,{} , {}, ) + addop("lgdt", [0x0F, 0x01], d2 , no_rm , {} ,{} , {}, ) + addop("lidt", [0x0F, 0x01], d3 , no_rm , {} ,{} , {}, ) + addop("lldt", [0x0F, 0x00], d2 , no_rm , {} ,{} , {}, ) + addop("lmsw", [0x0F, 0x01], d6 , no_rm , {} ,{} , {}, ) + + #ddop("lods", [0xAC], noafs, no_rm , {w8:(0,0)} ,{} , {}, ) + addop("lodsb", [0xAC], noafs, no_rm , {} ,{w8:True} , {}, ) + addop("lodsd", [0xAD], noafs, no_rm , {} ,{w8:False} , {}, ) + + addop("loop", [0xE2], noafs, [s08] , {} ,{} , {bkf:True,spf:True,dtf:True}) + addop("loope", [0xE1], noafs, [s08] , {} ,{} , {bkf:True,spf:True,dtf:True}) + addop("loopne",[0xE0], noafs, [s08] , {} ,{} , {bkf:True,spf:True,dtf:True}) + + addop("lsl", [0x0F, 0x03], noafs, [rmr] , {} ,{} , {}, ) + + addop("ltr", [0x0F, 0x00], d3 , no_rm , {} ,{wd:True} , {}, ) + + addop("mfence",[0x0F, 0xAE], d6 , no_rm , {} ,{} , {}, ) + + addop("mov", [0x88], noafs, [rmr] , {w8:(0,0),sw:(0,1)},{} , {}, ) + addop("mov", [0xA0], noafs, [r_eax,mim] , {w8:(0,0)} ,{} , {}, ) + addop("mov", [0xA2], noafs, [mim,r_eax] , {w8:(0,0)} ,{} , {}, ) + + addop("mov", [0xB0], reg , [imm] , {w8:(0,3)} ,{} , {}, ) + addop("mov", [0x0F, 0x20], noafs, [rmr] , {sw:(1,1)} ,{cr:True} , {}, ) + addop("mov", [0x0F, 0x21], noafs, [rmr] , {sw:(1,1)} ,{dr:True} , {}, ) + addop("mov", [0x8C], noafs, [rmr] , {sw:(0,1)} ,{sg:True,sw:True} , {}, ) + addop("mov", [0xC6], d0 , [imm] , {w8:(0,0)} ,{} , {}, ) + + addop("movnti",[0x0F, 0xC3], noafs, [rmr] , {} ,{} , {}, ) + + addop("movsb", [0xA4], noafs, no_rm , {} ,{w8:True} , {}, ) + addop("movsd", [0xA5], noafs, no_rm , {} ,{w8:False} , {}, ) + addop("movsx", [0x0F, 0xBE], noafs, [rmr] , {se:(1,0)} ,{} , {}, ) + addop("movzx", [0x0F, 0xB6], noafs, [rmr] , {se:(1,0)} ,{} , {}, ) + + addop("mul", [0xF6], d4 , no_rm , {w8:(0,0)} ,{} , {}, ) + + addop("neg", [0xF6], d3 , no_rm , {w8:(0,0)} ,{} , {}, ) + addop("nop", [0x0F, 0x1F], d0 , no_rm , {} ,{} , {}, ) + addop("not", [0xF6], d2 , no_rm , {w8:(0,0)} ,{} , {}, ) + + addop("or", [0x0C], noafs, [r_eax,imm] , {w8:(0,0)} ,{} , {}, ) + addop("or", [0x80], d1, [imm] , {w8:(0,0),se:(0,1)},{} , {}, ) + addop("or", [0x08], noafs, [rmr] , {w8:(0,0),sw:(0,1)},{} , {}, ) + + addop("out", [0xE6], noafs, [u08,r_eax] , {w8:(0,0)} ,{} , {}, ) + addop("out", [0xEE], noafs, [r_dx,r_eax] , {w8:(0,0)} ,{} , {}, ) + addop("outs", [0x6E], noafs, no_rm , {w8:(0,0)} ,{} , {}, ) + + addop("pause", [0xF3, 0x90], noafs, no_rm , {} ,{} , {}, ) + + addop("pop", [0x58], reg , no_rm , {} ,{} , {}, ) + addop("pop", [0x8F], d0 , no_rm , {} ,{} , {}, ) + addop("popad", [0x61], noafs, no_rm , {} ,{} , {}, ) + addop("popfd", [0x9D], noafs, no_rm , {} ,{} , {}, ) + + addop("prefetch",[0x0F, 0x18], d0 , no_rm , {} ,{} , {}, ) + addop("prefetch",[0x0F, 0x18], d1 , no_rm , {} ,{} , {}, ) + addop("prefetch",[0x0F, 0x18], d2 , no_rm , {} ,{} , {}, ) + addop("prefetch",[0x0F, 0x18], d3 , no_rm , {} ,{} , {}, ) + + addop("push", [0x68], noafs, [imm] , {se:(0,1)} ,{} , {}, ) + addop("push", [0x50], reg , no_rm , {} ,{} , {}, ) + addop("push", [0xFF], d6 , no_rm , {} ,{} , {}, ) + addop("pushad",[0x60], noafs, no_rm , {} ,{} , {}, ) + addop("pushfd",[0x9C], noafs, no_rm , {} ,{} , {}, ) + + addop("rcl", [0xD0], d2 , [im1] , {w8:(0,0)} ,{} , {}, ) + addop("rcl", [0xD2], d2 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("rcl", [0xC0], d2 , [u08] , {w8:(0,0)} ,{} , {}, ) + + addop("rcr", [0xD0], d3 , [im1] , {w8:(0,0)} ,{} , {}, ) + addop("rcr", [0xD2], d3 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("rcr", [0xC0], d3 , [u08] , {w8:(0,0)} ,{} , {}, ) + + addop("rol", [0xD0], d0 , [im1] , {w8:(0,0)} ,{} , {}, ) + addop("rol", [0xD2], d0 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("rol", [0xC0], d0 , [u08] , {w8:(0,0)} ,{} , {}, ) + + addop("ror", [0xD0], d1 , [im1] , {w8:(0,0)} ,{} , {}, ) + addop("ror", [0xD2], d1 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("ror", [0xC0], d1 , [u08] , {w8:(0,0)} ,{} , {}, ) + + addop("rdmsr", [0x0F, 0x32], noafs, no_rm , {} ,{} , {}, ) + addop("rdpmc", [0x0F, 0x33], noafs, no_rm , {} ,{} , {}, ) + addop("rdtsc", [0x0F, 0x31], noafs, no_rm , {} ,{} , {}, ) + + addop("ret", [0xC3], noafs, no_rm , {} ,{} , {bkf:True} ) + addop("retf", [0xCB], noafs, no_rm , {} ,{} , {bkf:True}, ) + + addop("ret", [0xC2], noafs, [u16] , {} ,{} , {bkf:True}, ) + addop("retf", [0xCA], noafs, [u16] , {} ,{} , {bkf:True}, ) + + addop("rms", [0x0F, 0xAA], noafs, no_rm , {} ,{} , {}, ) + addop("sahf", [0x9E], noafs, no_rm , {} ,{} , {}, ) + + + addop("sal", [0xC0], d4 , [u08] , {w8:(0,0)} ,{} , {}, ) + addop("sal", [0xC0], d6 , [u08] , {w8:(0,0)} ,{} , {}, ) + + addop("sal", [0xC1], d4 , [u08] , {w8:(0,0)} ,{} , {}, ) + addop("sal", [0xC1], d6 , [u08] , {w8:(0,0)} ,{} , {}, ) + + addop("sal", [0xD1], d4 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("sal", [0xD1], d6 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + + addop("sal", [0xD3], d4 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("sal", [0xD3], d6 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + """ + addop("sal", [0xD2], d4 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("sal", [0xC0], d4 , [u08] , {w8:(0,0)} ,{} , {}, ) + """ , {} + + addop("sal", [0xD0], d6 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("sar", [0xD0], d7 , [im1] , {w8:(0,0)} ,{} , {}, ) + + addop("sar", [0xD2], d6 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("sar", [0xD2], d7 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("sar", [0xC0], d7 , [u08] , {w8:(0,0)} ,{} , {}, ) + + addop("shl", [0xD0], d4 , [im1] , {w8:(0,0)} ,{} , {}, ) + addop("shl", [0xD2], d4 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("shl", [0xC0], d4 , [u08] , {w8:(0,0)} ,{} , {}, ) + + addop("shr", [0xD0], d5 , [im1] , {w8:(0,0)} ,{} , {}, ) + addop("shr", [0xD2], d5 , [r_cl] , {w8:(0,0)} ,{} , {}, ) + addop("shr", [0xC0], d5 , [u08] , {w8:(0,0)} ,{} , {}, ) + + addop("sbb", [0x1C], noafs, [r_eax,imm] , {w8:(0,0)} ,{} , {}, ) + addop("sbb", [0x80], d3, [imm] , {w8:(0,0),se:(0,1)},{} , {}, ) + addop("sbb", [0x18], noafs, [rmr] , {w8:(0,0),sw:(0,1)},{} , {}, ) + + #addop("scas", [0xAE], noafs, no_rm , {w8:(0,0)} ,{} , {}, ) + addop("scasb", [0xAE], noafs, no_rm , {} ,{w8:True} , {}, ) + addop("scasd", [0xAF], noafs, no_rm , {} ,{w8:False} , {}, ) + + + addop("set", [0x0F, 0x90], cond , [rmr] , {} ,{w8:True} , {}, ) + + addop("qfence",[0x0F, 0xAE], d7 , no_rm , {} ,{} , {}, ) + addop("sgdt", [0x0F, 0x01], d0 , no_rm , {} ,{} , {}, ) + + addop("shld", [0x0F, 0xA4], noafs, [rmr, u08] , {} ,{sw:True} , {}, ) + addop("shld_cl",[0x0F, 0xA5], noafs, [rmr] , {} ,{sw:True} , {}, ) + addop("shrd", [0x0F, 0xAC], noafs, [rmr, u08] , {} ,{sw:True} , {}, ) + addop("shrd_cl",[0x0F, 0xAD], noafs, [rmr] , {} ,{sw:True} , {}, ) + + addop("sidt", [0x0F, 0x01], d1 , no_rm , {} ,{} , {}, ) + addop("sldt", [0x0F, 0x00], d0 , no_rm , {} ,{} , {}, ) + addop("smsw", [0x0F, 0x01], d4 , no_rm , {} ,{} , {}, ) + addop("stc", [0xF9], noafs, no_rm , {} ,{} , {}, ) + addop("std", [0xFD], noafs, no_rm , {} ,{} , {}, ) + addop("sti", [0xFB], noafs, no_rm , {} ,{} , {}, ) + addop("stmxcsr",[0x0F, 0xAE], d3 , no_rm , {} ,{} , {}, ) + + #addop("stos", [0xAA], noafs, [r_eax] , {w8:(0,0)} ,{} , {}, ) + addop("stosb", [0xAA], noafs, no_rm , {} ,{w8:True} , {}, ) + addop("stosd", [0xAB], noafs, no_rm , {} ,{w8:False} , {}, ) + + addop("str", [0x0F, 0x00], d1 , no_rm , {} ,{} , {}, ) + + addop("sub", [0x2C], noafs, [r_eax,imm] , {w8:(0,0)} ,{} , {}, ) + addop("sub", [0x80], d5, [imm] , {w8:(0,0),se:(0,1)},{} , {}, ) + addop("sub", [0x28], noafs, [rmr] , {w8:(0,0),sw:(0,1)},{} , {}, ) + + """ , {} + #XXX dup opcode => modrm encoding , {} + addop("swapgs",[0x0F, 0x01], d7 , no_rm , {} ,{} , {}, ) + """ , {} + addop("syscall",[0x0F, 0x05], noafs, no_rm , {} ,{} , {bkf:True}, ) + addop("sysenter",[0x0F, 0x34], noafs, no_rm , {} ,{} , {bkf:True}, ) + addop("sysexit",[0x0F, 0x35], noafs, no_rm , {} ,{} , {bkf:True}, ) + addop("sysret",[0x0F, 0x07], noafs, no_rm , {} ,{} , {bkf:True}, ) + + addop("test", [0xA8], noafs, [r_eax,imm] , {w8:(0,0)} ,{} , {}, ) + addop("test", [0xF6], d0, [imm] , {w8:(0,0)} ,{} , {}, ) + addop("test", [0x84], noafs, [rmr] , {w8:(0,0)} ,{sw:True} , {}, ) + + addop("ud2", [0x0F, 0x0B], noafs, no_rm , {} ,{} , {}, ) + addop("verr", [0x0F, 0x00], d4 , no_rm , {} ,{} , {}, ) + addop("verw", [0x0F, 0x00], d5 , no_rm , {} ,{} , {}, ) + #ddop("wait", [0x9B], noafs, no_rm , {} ,{} , {}, ) + addop("wbinvd",[0x0F, 0x09], noafs, no_rm , {} ,{} , {}, ) + addop("wrmsr", [0x0F, 0x30], noafs, no_rm , {} ,{} , {}, ) + + addop("xadd", [0x0F, 0xC0], noafs, [rmr] , {w8:(1,0)} ,{} , {}, ) + + addop("xchg", [0x90], reg , [r_eax] , {} ,{} , {}, ) + + addop("nop", [0x90], noafs, no_rm , {} ,{} , {}, ) + + addop("xchg", [0x86], noafs, [rmr] , {w8:(0,0)} ,{} , {}, ) + + addop("xlat", [0xD7], noafs, no_rm , {} ,{} , {}, ) + + addop("xor", [0x34], noafs, [r_eax,imm] , {w8:(0,0)} ,{} , {}, ) + addop("xor", [0x80], d6, [imm] , {w8:(0,0),se:(0,1)},{} , {}, ) + addop("xor", [0x30], noafs, [rmr] , {w8:(0,0),sw:(0,1)},{} , {}, ) + + addop("monitor",[0x0F, 0x01, 0xC8],noafs, no_rm , {} ,{} , {}, ) + addop("mwait", [0x0F, 0x01, 0xC9], noafs, no_rm , {} ,{} , {}, ) + + #x87 fpu , {} + addop("f2xm1", [0xD9, 0xF0], noafs, no_rm , {} ,{} , {}, ) + addop("fabs", [0xD9, 0xE1], noafs, no_rm , {} ,{} , {}, ) + + addop("fadd", [0xD8], d0, no_rm , {sd:(0,2)} ,{} , {}, ) + addop("fadd", [0xD8, 0xC0], reg, [r_eax] , {sw:(0,2)} ,{sd:False,sw:False},{}, ) + addop("fiadd", [0xDA], d0, no_rm , {wd:(0,2)} ,{} , {}, ) + addop("faddp", [0xDE, 0xC0], reg, no_rm , {} ,{sd:False} , {}, ) + + addop("fbld", [0xDF], d4, no_rm , {} ,{} , {}, ) + addop("fbstp", [0xDF], d6, no_rm , {} ,{} , {}, ) + + addop("fchs", [0xD9, 0xE0], noafs, no_rm , {} ,{} , {}, ) + #ddop("fclex", [0x9B, 0xDB, 0xE2], noafs, no_rm , {} ,{} , {}, ) #XXX no mnemo + addop("fnclex",[0xDB, 0xE2], noafs, no_rm , {} ,{} , {}, ) + + addop("fcmovb",[0xDA, 0xC0], reg, [r_eax] , {} ,{} , {}, ) + addop("fcmove",[0xDA, 0xC8], reg, [r_eax] , {} ,{} , {}, ) + addop("fcmovbe",[0xDA, 0xD0], reg, [r_eax] , {} ,{} , {}, ) + addop("fcmovu",[0xDA, 0xD8], reg, [r_eax] , {} ,{} , {}, ) + addop("fcmovnb",[0xDB, 0xC0], reg, [r_eax] , {} ,{} , {}, ) + addop("fcmovne",[0xDB, 0xC8], reg, [r_eax] , {} ,{} , {}, ) + addop("fcmovnbe",[0xDB, 0xD0], reg, [r_eax] , {} ,{} , {}, ) + addop("fcmovnu",[0xDB, 0xD8], reg, [r_eax] , {} ,{} , {}, ) + + addop("fcom", [0xD8], d2, no_rm , {sd:(0,2)} ,{} , {}, ) + addop("fcom", [0xD8, 0xD0], reg, no_rm , {} ,{sd:False} , {}, ) + addop("fcomp", [0xD8], d3, no_rm , {sd:(0,2)} ,{} , {}, ) + addop("fcomp", [0xD8, 0xD8], reg, no_rm , {} ,{sd:False} , {}, ) + addop("fcompp",[0xDE, 0xD9], noafs, no_rm , {} ,{} , {}, ) + + addop("fcomi", [0xDB, 0xF0], reg, no_rm , {} ,{sd:False} , {}, ) + addop("fcomip",[0xDF, 0xF0], reg, no_rm , {} ,{sd:False} , {}, ) + addop("fucomi",[0xDB, 0xE8], reg, no_rm , {} ,{sd:False} , {}, ) + addop("fucomi",[0xDF, 0xE8], reg, no_rm , {} ,{sd:False} , {}, ) + + addop("ficom", [0xDA], d2, no_rm , {wd:(0,2)} ,{} , {}, ) + addop("ficomp",[0xDA], d3, no_rm , {wd:(0,2)} ,{} , {}, ) + + + addop("fdiv", [0xD8], d6, no_rm , {sd:(0,2)} ,{} , {}, ) + addop("fdiv", [0xD8, 0xF0], reg, [r_eax] , {sw:(0,2)} ,{sd:False,sw:False},{}, ) + addop("fidiv", [0xDA], d6, no_rm , {wd:(0,2)} ,{} , {}, ) + addop("fdivp", [0xDE, 0xF8], reg, no_rm , {} ,{sd:False} , {}, ) + + addop("fdivr", [0xD8], d7, no_rm , {sd:(0,2)} ,{} , {}, ) + addop("fdivr", [0xD8, 0xF8], reg, [r_eax] , {sw:(0,2)} ,{sd:False,sw:False},{}, ) + addop("fidivr",[0xDA], d7, no_rm , {wd:(0,2)} ,{} , {}, ) + addop("fdivrp",[0xDE, 0xF0], reg, no_rm , {} ,{sd:False} , {}, ) + + addop("ffree", [0xDD, 0xC0], reg, no_rm , {} ,{sd:False} , {}, ) + + addop("fwait", [0x9B], noafs, no_rm , {} ,{} , {}, ) + + addop("fild", [0xDB], d0, no_rm , {wd:(0,2)} ,{wd:False} , {}, ) + addop("fild", [0xDF], d5, no_rm , {} ,{sd:True,wd:False}, {}, ) #XXX 64 + + addop("fincstp",[0xD9, 0xF7], noafs, no_rm , {} ,{} , {}, ) + + #ddop("finit", [0x9B, 0xDB, 0xE3], noafs, no_rm , {} ,{} , {}, ) #XXX no mnemo + addop("fninit",[0xDB, 0xE3], noafs, no_rm , {} ,{} , {}, ) + + addop("fist", [0xDB], d2, no_rm , {wd:(0,2)} ,{wd:False} , {}, ) + addop("fistp", [0xDB], d3, no_rm , {wd:(0,2)} ,{wd:False} , {}, ) + addop("fistp", [0xDF], d7, no_rm , {} ,{sd:False} , {}, ) #XXX 64 + addop("fisttp",[0xDB], d1, no_rm , {wd:(0,2)} ,{wd:False} , {}, ) + addop("fisttp",[0xDD], d1, no_rm , {} ,{sd:False} , {}, ) #XXX 64 + + + + addop("fmul", [0xD8], d1, no_rm , {sd:(0,2)} ,{} , {}, ) + addop("fmul", [0xD8, 0xC8], reg, [r_eax] , {sw:(0,2)} ,{sd:False,sw:False},{}, ) + addop("fimul", [0xDA], d1, no_rm , {wd:(0,2)} ,{} , {}, ) + addop("fmulp", [0xDE, 0xC8], reg, no_rm , {} ,{sd:False} , {}, ) + + + addop("frstor",[0xDD], d4, no_rm , {} ,{wd:False} , {}, ) #XXX 94/108 + + #ddop("fsave", [0x9B, 0xDD], d6, no_rm , {} ,{wd:False} , {}, ) #XXX no mnemo + addop("fnsave",[0xDD], d6, no_rm , {} ,{wd:False} , {}, ) #XXX 94/108 + + + addop("fst", [0xD9], d2, no_rm , {sd:(0,2)} ,{} , {}, ) + addop("fst", [0xDD, 0xD0], reg, no_rm , {} ,{sd:False} , {}, ) + addop("fstp", [0xD9], d3, no_rm , {sd:(0,2)} ,{sd:True} , {}, ) + addop("fstp", [0xDB], d7, no_rm , {} ,{sd:False} , {}, ) #XXX 80 + addop("fstp", [0xDD, 0xD8], reg, no_rm , {} ,{sd:False} , {}, ) + + #ddop("fstcw", [0x9B, 0xD9], d7, no_rm , {} ,{wd:False} , {}, ) #XXX no mnemo + addop("fnstcw",[0xD9], d7, no_rm , {} ,{wd:True} , {}, ) + #ddop("fstenv",[0x9B, 0xD9], d6, no_rm , {} ,{wd:False} , {}, ) #XXX no mnemo + addop("fnstenv",[0xD9], d6, no_rm , {} ,{wd:False} , {}, ) + + addop("fnop", [0xD9, 0xD0], noafs, no_rm , {} ,{sd:False} , {}, ) + + addop("fpatan",[0xD9, 0xF3], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fprem", [0xD9, 0xF8], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fprem1",[0xD9, 0xF5], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fptan", [0xD9, 0xF2], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("frndint",[0xD9, 0xFC], noafs, no_rm , {} ,{sd:False} , {}, ) + + addop("fscale",[0xD9, 0xFD], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fsin", [0xD9, 0xFE], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fsincos",[0xD9, 0xFB], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fsqrt", [0xD9, 0xFA], noafs, no_rm , {} ,{sd:False} , {}, ) + + addop("fcos", [0xD9, 0xFF], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fdecstp",[0xD9, 0xF6], noafs, no_rm , {} ,{sd:False} , {}, ) + + addop("fld", [0xD9], d0, no_rm , {sd:(0,2)} ,{} , {}, ) + addop("fld", [0xDB], d5, no_rm , {} ,{sd:False} , {}, ) #XXX 80 + addop("fld", [0xD9, 0xC0], reg, no_rm , {} ,{sd:False} , {}, ) + + addop("fldcw", [0xD9], d5, no_rm , {} ,{wd:True} , {}, ) + addop("fldenv",[0xD9], d4, no_rm , {} ,{wd:False} , {}, ) + + addop("fld1", [0xD9, 0xE8], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fldl2t",[0xD9, 0xE9], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fldl2e",[0xD9, 0xEA], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fldpi", [0xD9, 0xEB], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fldlg2",[0xD9, 0xEC], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fldln2",[0xD9, 0xED], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fldz", [0xD9, 0xEE], noafs, no_rm , {} ,{sd:False} , {}, ) + + + #ddop("fstsw", [0x9B, 0xDD], d7, no_rm , {} ,{wd:False} , {}, ) #XXX no mnemo + addop("fnstsw",[0xDD], d7, no_rm , {} ,{wd:True} , {}, ) + #ddop("fstsw",[0x9B, 0xDF, 0xE0], noafs, no_rm , {} ,{wd:False} , {}, ) #XXX no mnemo + addop("fnstsw",[0xDF, 0xE0], noafs, no_rm , {} ,{wd:False} , {}, ) + + addop("fsub", [0xD8], d4, no_rm , {sd:(0,2)} ,{} , {}, ) + addop("fsub", [0xD8, 0xE0], reg, [r_eax] , {sw:(0,2)} ,{sd:False,sw:False},{}, ) + addop("fisub", [0xDA], d4, no_rm , {wd:(0,2)} ,{} , {}, ) + addop("fsubp", [0xDE, 0xE8], reg, no_rm , {} ,{sd:False} , {}, ) + + addop("fsubr", [0xD8], d5, no_rm , {sd:(0,2)} ,{} , {}, ) + addop("fsubr", [0xD8, 0xE8], reg, [r_eax] , {sw:(0,2)} ,{sd:False,sw:False},{}, ) + addop("fisubr",[0xDA], d5, no_rm , {wd:(0,2)} ,{} , {}, ) + addop("fsubrp",[0xDE, 0xE0], reg, no_rm , {} ,{sd:False} , {}, ) + + addop("ftst", [0xD9, 0xE4], noafs, no_rm , {} ,{sd:False} , {}, ) + + addop("fucom", [0xDD, 0xE0], reg, no_rm , {} ,{sd:False} , {}, ) + addop("fucomp",[0xDD, 0xE8], reg, no_rm , {} ,{sd:False} , {}, ) + addop("fucompp",[0xDA, 0xE9], noafs, no_rm , {} ,{sd:False} , {}, ) + + addop("fxam", [0xD9, 0xE5], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fxch", [0xD9, 0xC8], reg, no_rm , {} ,{sd:False} , {}, ) + + addop("fxrstor",[0x0f, 0xAE], d1, no_rm , {} ,{sd:False} , {}, ) #XXX 512 + addop("fxrsave",[0x0f, 0xAE], d0, no_rm , {} ,{sd:False} , {}, ) #XXX 512 + addop("fxtract",[0xD9, 0xF4], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fyl2x", [0xD9, 0xF1], noafs, no_rm , {} ,{sd:False} , {}, ) + addop("fyl2xp1",[0xD9, 0xF9], noafs, no_rm , {} ,{sd:False} , {}, ) + pm = self.db_mnemo[0x9c] + self.pushfw_m = mnemonic(pm.name, pm.opc, pm.afs, pm.rm, pm.modifs, pm.modifs_orig, None)#, pm.sem) + self.pushfw_m.name = "pushfw" + + + +x86mndb = x86allmncs() + +class x86_mnemo_metaclass(type): + rebuilt_inst = True + + def dis(cls, op, admode = u32, opmode = u32, sex = 0): + i = cls.__new__(cls) + i.__init__(admode, opmode, sex) + i.size_op = opmode + i.size_ad = admode + u = i._dis(op) + if not u: + return None + #XXX error in scasd mnemo 16 bit + if i.m.name == "scasd": + if i.size_op == u16: + i.m.name = "scasw" + + return i + def asm(cls, l, symbol_off = []): + i = cls.__new__(cls) + i.__init__(admode = u32, opmode = u32, sex = 0) + return i._asm(l, symbol_off) + + + def has_symb(cls, a): + if type(a) in [int, long]+tab_int_size.keys(): + return False + if x86_afs.symb in a: + return True + return False + + def fix_symbol(cls, a, symbol_pool = None): + if type(a) in [int, long]+tab_int_size.keys(): + return a + + cp = dict(a) + if not x86_afs.symb in cp: + return cp + + if not symbol_pool: + del cp[x86_afs.symb] + if not x86_afs.imm in cp: + cp[x86_afs.imm] = 0 + return cp + + imm_total = 0 + if x86_afs.imm in cp: + imm_total+=cp[x86_afs.imm] + for s in cp[x86_afs.symb]: + base_ad = symbol_pool.s['base_address'].offset_g + imm_total+=cp[x86_afs.symb][s]*(symbol_pool.s[s.name].offset_g+base_ad) + + cp[x86_afs.imm] = imm_total + del cp[x86_afs.symb] + + + return cp + + def is_mem(cls, a): + return x86_afs.ad in a and a[x86_afs.ad] + + def get_label(cls, a): + if not x86_afs.symb in a: + return None + n = a[x86_afs.symb] + if len(n)!=1: + return None + k = n.keys()[0] + if n[k] != 1: + return None + return k + + def get_symbols(cls, a): + if not x86_afs.symb in a: + return None + return a[x86_afs.symb].items() + def set_symbols(cls, a, s): + print a, s + def names2symbols(cls, a, s_dict): + all_s = a[x86_afs.symb] + for name, s in s_dict.items(): + count = all_s[name] + del(all_s[name]) + all_s[s] = count + + +class x86_mn: + __metaclass__ = x86_mnemo_metaclass + def __init__(self, admode = u32, opmode = u32, sex = 0): + self.admode = admode + self.opmode = opmode + self.mnemo_mode = self.admode + + self.size_op = u32 + self.size_ad = u32 + + @classmethod + def prefix2hex(self, prefix): + return reduce(lambda x,y:x+chr(y), prefix, "") + + + def breakflow(self): + return self.m.modifs[bkf] + def splitflow(self): + return self.m.modifs[spf] + def dstflow(self): + return self.m.modifs[dtf] + + def getnextflow(self): + return self.offset+self.l + + def getdstflow(self): + if len(self.arg) !=1: + print ValueError('should be 1 arg %s'%str(self)) + return [] + a = self.arg[0] + if is_imm(a) and not x86_afs.symb in a: + dst = (self.offset+self.l+a[x86_afs.imm])&0xFFFFFFFF + out = [dst] + else: + out = [a] + return out + + def setdstflow(self, dst): + if len(self.arg) !=1: + print ValueError('should be 1 arg %s'%str(self)) + return + if len(dst)==0: + return + if len(dst)!=1: + raise ValueError('should be 1 dst') + l = dst[0] + + #patch only known symbols + if l.offset !=None: + self.arg = [{x86_afs.symb:{l:1}}] + + def fixdst(self, lbls, my_offset, is_mem): + if len(self.arg) !=1: + raise ValueError('should be 1 arg %s'%str(self)) + a = self.arg[0] + l = a[x86_afs.symb].keys()[0] + offset = lbls[l.name] + if is_mem: + arg = {x86_afs.ad:is_mem, x86_afs.imm:offset} + else: + arg = {x86_afs.imm:offset-(my_offset)} + + self.arg = [arg] + + def is_subcall(self): + return self.m.name == 'call' + + def __str__(self): + if type(self.instr_string) is str: + return self.instr_string + + args_str = "" + for p in self.prefix: + if p in prefix_dic_inv: + args_str += prefix_dic_inv[p]+" " + args_str+="%-10s"%(self.m.name) + + for a in self.arg: + if type(a) in [int, long]: + raise ValueError("should be intsized %s"%str(a)) + if type(a) in tab_int_size: + raise ValueError("should be dict.. %s"%str(a)) + elif type(a) == dict: + args_str+="%s, "%dict_to_ad(a, self.m.modifs, self.mnemo_mode) + else: + raise ValueError("arg zarbi %s"%str(a)) + return args_str[:-2] + + def intsize(self, im, ext = False): + if ext: + return [uint16, uint32][self.mnemo_mode == u32](im) + if self.m.modifs[w8]: + return uint8(im) + if self.mnemo_mode == u32: + return uint32(im) + elif self.mnemo_mode == u16: + return uint16(im) + else: + raise ValueError('unknown mnemo mode %s'%str(im)) + + def _dis(self, bin): + size_op = self.size_op + size_ad = self.size_ad + + + + if type(bin) == str: + from miasm.core.bin_stream import bin_stream + + bin = bin_stream(bin) + + init_offset = bin.offset + + try: + #find mnemonic + l = x86mndb.db_mnemo + index = 0 + m = None + read_prefix = [] + prefix_done =False + while True: + c = ord(bin.readbs()) + if not prefix_done and c in x86_afs.x86_prefix: + read_prefix.append(c) + continue + else: + prefix_done = True + if l[c] == None: + log.debug( "unknown mnemo") + break + if isinstance(l[c] ,mnemonic): + m = l[c] + break + if type(l[c]) == list: + l = l[c] + + if m == None: + return None + self.m = m + + log.debug(m) + log.debug("prefix: %s"%str(read_prefix)) + + self.mnemo_mode = self.admode + if 0x66 in read_prefix: + self.mnemo_mode = [u16,u32][self.mnemo_mode==u16] + self.size_op = [u16,u32][size_op == u16] + if 0x67 in read_prefix: + self.size_ad = [u16,u32][size_ad == u16] + + + + #parse mnemonic args + mnemo_args = [] + + afs, dibs = m.afs, m.rm + modrm = None + #digit + if afs in [d0, d1, d2, d3, d4, d5, d6, d7]: + re, modr = x86mndb.get_afs(bin, c, self.size_ad) + mnemo_args.append(modr) + mnemo_args[-1][x86_afs.size] = self.mnemo_mode + + if m.modifs[sd] is not None: + if m.modifs[sd]: + mnemo_args[-1][x86_afs.size] = x86_afs.f32 + else: + mnemo_args[-1][x86_afs.size] = x86_afs.f64 + + if m.modifs[w8]: + mnemo_args[-1][x86_afs.size] = x86_afs.u08 + if m.modifs[wd]: + #XXX check (for fnst??)= + mnemo_args[-1][x86_afs.size] = x86_afs.u16 + #+reg + elif afs == reg: + mafs = dict(x86mndb.get_afs_re(c&(0xFF^mask_reg))) + if m.modifs[w8]: + mafs[x86_afs.size] = x86_afs.u08 + else: + mafs[x86_afs.size] = self.mnemo_mode + + mnemo_args.append(mafs) + #rm mod + elif afs in [noafs, cond]: + if rmr in m.rm: + c = ord(bin.readbs()) + re, modr = x86mndb.get_afs(bin, c, self.size_ad) + + reg_cat = 0 + if m.modifs[dr]: + reg_cat+=0x8 + if m.modifs[cr]: + reg_cat+=0x10 + if m.modifs[sg]: + reg_cat+=0x20 + mafs = dict(x86mndb.get_afs_re(re+reg_cat)) + if m.modifs[w8]: + mafs[x86_afs.size] = x86_afs.u08 + else: + mafs[x86_afs.size] = self.mnemo_mode + + mnemo_args.append(mafs) + mnemo_args.append(modr) + + + mnemo_args[-1][x86_afs.size] = self.mnemo_mode + if m.modifs[w8] : + mnemo_args[-1][x86_afs.size] = x86_afs.u08 + if m.modifs[se] !=None and not (imm in dibs or ims in dibs): + mnemo_args[-1][x86_afs.size] = [x86_afs.u08, x86_afs.u16][m.modifs[se]] + + + if m.modifs[wd]: + mnemo_args[-1][x86_afs.size] = x86_afs.u16 + mnemo_args[-2][x86_afs.size] = x86_afs.u16 + if m.modifs[sg]: + mnemo_args[-2][x86_afs.size] = x86_afs.size_seg + if afs == cond and m.name.startswith('set'): + mnemo_args.pop(0) + + + elif afs == cond: + pass + else: + raise ValueError('bug in %s %d'%(name, afs)) + + #swap args? + if m.modifs[sw]: + mnemo_args.reverse() + + + dib_out = [] + for dib in dibs: + #unsigned + log.debug(m.modifs) + if dib in [u08, s08, u16, s16, u32, s32]: + if self.mnemo_mode !=u32: + if dib == u32: + dib = u16 + if dib == s32: + dib = s16 + l = struct.calcsize(x86_afs.dict_size[dib]) + d = struct.unpack(x86_afs.dict_size[dib], bin.readbs(l))[0] + d = self.intsize(d) + + dib_out.append({x86_afs.imm:d}) + elif dib in [imm, ims]: + taille, fmt, t = x86mndb.get_im_fmt(m.modifs, self.mnemo_mode, dib) + dib_out.append({x86_afs.imm:self.intsize(struct.unpack(fmt, bin.readbs(taille))[0], dib==ims)}) + + elif dib in [im1, im3]: + dib_out.append({im1:{x86_afs.imm:self.intsize(1)},im3:{x86_afs.imm:self.intsize(3)}}[dib]) + elif dib == rmr: + continue + elif dib == r_eax: + mafs = dict(x86mndb.get_afs_re(x86_afs.reg_dict[x86_afs.r_eax])) + if m.modifs[w8]: + mafs[x86_afs.size] = x86_afs.u08 + else: + mafs[x86_afs.size] = self.mnemo_mode + + r = mafs + + if len(mnemo_args): + if m.modifs[sw]: + mnemo_args = mnemo_args+[r] + else: + mnemo_args = [r]+mnemo_args + + else: + dib_out.append(r) + + elif dib == mim: + l = struct.calcsize(x86_afs.dict_size[self.size_ad]) + d = struct.unpack(x86_afs.dict_size[self.size_ad], bin.readbs(l))[0] + d = uint32(d) + + + size = [self.mnemo_mode, x86_afs.u08][m.modifs[w8]] + dib_out.append({x86_afs.ad:True, x86_afs.size:size, x86_afs.imm:d}) + elif dib in [r_cl, r_dx]: + dib_out.append(dib) + pass + + + else: + raise ValueError('bad dib!!%X'%dib) + + mnemo_args+=dib_out + + for a in mnemo_args: + for p in read_prefix: + if is_address(a) and p in prefix_seg.values(): + a[x86_afs.segm]=prefix_seg_inv[p] + continue + + + + t_len = bin.offset-init_offset + bin.offset = init_offset + bytes_ret = bin.readbs(t_len) + self.offset = init_offset + self.instr_string = None + self.l = t_len + self.b = bytes_ret + self.m = m + self.arg = mnemo_args + self.prefix = read_prefix + + #XXX hack + if 0x66 in read_prefix and self.m.name == "pushfd": + self.m = x86mndb.pushfw_m + if 0x66 in read_prefix and self.m.name == "lodsd": + self.m.name = "lodsw" + if 0x66 in read_prefix and self.m.name == "stosd": + self.m.name = "stosw" + if 0x66 in read_prefix and self.m.name == "movsd": + self.m.name = "movsw" + + return True + + + except IOError: + log.warning( "cannot dis: not enougth bytes") + return None + + @classmethod + def parse_mnemo(self, l): + tokens = [t for t in shlex.shlex(l)] + prefix = [] + if not tokens: + raise ValueError('cannot parse mnemo?', l) + while True: + name = tokens[0] + tokens = tokens[1:] + + if name in prefix_dic: + prefix.append(name) + continue + break + + args = [] + arg = [] + s = ',' + while s in tokens: + i = tokens.index(s) + args.append(tokens[:i]) + tokens = tokens[i+1:] + args.append(tokens) + args = map(lambda x: reduce(lambda x,y: x+' '+y, x, ""), args) + + if args == ['']: + return prefix, name, [] + + for a in args: + if x86_afs.segm in a: + prefix.append(x86_afs.reg_sg.index(a[x86_afs.segm])) + + return prefix, name, args + + @classmethod + def parse_address(self, a): + return parse_ad(a) + + def asm_parse(self, l): + log.debug("asm: %s"%l) + + prefix, name, args = x86_mn.parse_mnemo(l) + prefix = [prefix_dic[x] for x in prefix] + + log.debug("name: %s"%name) + log.debug("args: %s"%str(args)) + + args_eval = [] + for a in args: + args_eval.append(x86_mn.parse_address(a)) + if x86_afs.segm in args_eval[-1]: + prefix.append(prefix_seg[args_eval[-1][x86_afs.segm]]) + del args_eval[-1][x86_afs.segm] + + #XXX test if symbol in arg and replace with imm... for pre asm + if x86_afs.symb in args_eval[-1]: + log.debug('pre-assembling with symbol! %s'%str(args_eval[-1][x86_afs.symb])) + if not x86_afs.imm in args_eval[-1]: + args_eval[-1][x86_afs.imm] = 0 + + del args_eval[-1][x86_afs.symb] + + log.info("prefix:%s"%str(prefix)) + log.info('eval: %s'%str(args_eval)) + + + + #search all candidates + log.debug('Find mnemo') + candidate = x86mndb.find_mnemo(name) + if not candidate: + log.warning("no mnemonic found") + + can_be_16_32 = True + log.debug("candi:") + for c in candidate: + if c.modifs[sd] or c.modifs[wd]: + can_be_16_32 = False + log.debug( c) + + + + + #test for 16/32 bit mode + if can_be_16_32: + self.mnemo_mode = None + for a in args_eval: + #32 priority + if (is_reg(a)) and a[x86_afs.size] == u32: + self.mnemo_mode = u32 + break + + #XXX if eax, cx .... 32 bit bug + if (is_reg(a) or is_address(a)) and a[x86_afs.size] == u16 and self.mnemo_mode == None: + self.mnemo_mode = u16 + break + + + if self.mnemo_mode == None: + self.mnemo_mode = u32 + + if self.mnemo_mode == u16: + log.debug("16 bit mode detected for %s"%str(l)) + prefix.append(0x66) + if name in ["movzx", "movsx"]: + if args_eval[0][x86_afs.size] == u16: + args_eval[0][x86_afs.size] = u32 + if args_eval[0][x86_afs.ad]: + args_eval[0][x86_afs.ad] = u32 + else: + + for a in args_eval: + if a[x86_afs.size] == u16: + a[x86_afs.size] = u32 + if a[x86_afs.ad]: + a[x86_afs.ad] = u32 + + else: + self.mnemo_mode = u32 + + log.info('eval2: %s'%str(args_eval)) + + modifs = dict([[x, None] for x in [w8, se, sw, ww, sg, dr, cr, ft, w64, sd, wd]]) + modifs[sw] = False + + + #spot dr/cr regs + for a in args_eval: + for x in a: + if type(x) in [int, long] and x>=0x100: + tmp = a[x] + for y in mask_drcrsg: + if x & mask_drcrsg[y]: + modifs[y] = True + + + candidate_out = [] + for c in candidate: + + if (modifs[cr] or c.modifs[cr]) and modifs[cr] != c.modifs[cr]: + continue + if (modifs[dr] or c.modifs[dr]) and modifs[dr] != c.modifs[dr]: + continue + + if (modifs[sg] or c.modifs[sg]) and modifs[sg] != c.modifs[sg]: + continue + + + args_sample = [dict(x) for x in args_eval] + + afs, dibs = c.afs, c.rm + log.debug(c) + + parsed_args = [] + parsed_val = [{}] + out_opc = [c.opc[:]] + opc_add = [] + + good_c = True + dib_out = [] + for dib in dibs: + if dib in [u08, s08, u16, s16, u32, s32]: + index_im = [-1, 0][afs == noafs] + + if len(args_sample)<=0: + good_c = False + break + if not x86_afs.imm in args_sample[index_im] or args_sample[index_im][x86_afs.ad]: + log.debug("not imm 1") + good_c = False + break + + + if self.mnemo_mode !=u32: + if dib == u32: + dib = u16 + if dib == s32: + dib = s16 + + size = dib + + v = check_imm_size(args_sample[index_im][x86_afs.imm], size) + if v == None: + log.debug("cannot encode this val in size %s %x!"%(size, args_sample[index_im][x86_afs.imm])) + good_c= False + break + + args_sample[index_im][x86_afs.size] = size + args_sample[index_im][x86_afs.imm] = tab_size2int[size](v) + + + opc_add.append({x86_afs.size:size, x86_afs.imm:args_sample[index_im][x86_afs.imm]}) + r = args_sample[index_im] + del args_sample[index_im] + dib_out.append(r) + + elif dib in [im1, im3]: + if x86_afs.imm in args_sample[-1] and args_sample[-1][x86_afs.imm] =={im1:1,im3:3}[dib]: + dib_out.append(args_sample.pop()) + else: + log.debug("not im val fixed") + good_c = False + break + + elif dib in [imm, ims]: + if len(args_sample)<=0: + good_c = False + break + if not x86_afs.imm in args_sample[-1] or args_sample[-1][x86_afs.ad]: + log.debug("not imm 2") + good_c = False + break + taille, fmt, t = x86mndb.get_im_fmt(c.modifs, self.mnemo_mode, dib) + r = args_sample.pop() + v = check_imm_size(r[x86_afs.imm], t) + if v == None: + log.debug("cannot encode this val in size %s %x!"%(t, int(r[x86_afs.imm]))) + good_c= False + break + r[x86_afs.imm] = tab_size2int[t](v) + opc_add.append({x86_afs.size:t, x86_afs.imm:r[x86_afs.imm]}) + + if c.modifs[se]: + r[x86_afs.size] = r[x86_afs.size] + r[x86_afs.imm] = tab_size2int[r[x86_afs.size]](r[x86_afs.imm]) + dib_out.append(r) + + + + elif dib == rmr: + continue + elif dib == r_eax: + if not args_sample or args_sample[0][x86_afs.ad]: + log.debug("not r_eax1") + good_c = False + break + size = args_sample[0][x86_afs.size] + + if not x86mndb.check_size_modif(size, c.modifs): + log.debug(' bad reg size') + good_c = False + break + if c.modifs[sw]: + index = 1 + if len(args_sample) !=2: + raise ValueError("sw in r_eax zarb") + else: + index = 0 + if not x86_afs.reg_dict[x86_afs.r_eax] in args_sample[index]: + log.debug("not r_eax2") + good_c = False + break + #add front + if size == x86_afs.u32: + args_sample[index][x86_afs.size] = self.mnemo_mode + r = args_sample[index] + del(args_sample[index]) + if len(args_sample) and not c.modifs[sw]: + parsed_args.append(r) + else: + dib_out.append(r) + + + elif dib in [r_cl, r_dx]: + index_im = [-1, 0][afs == noafs] + dib_tmp = dict(dib) + del(dib_tmp[x86_afs.size]) + del(args_sample[index_im][x86_afs.size]) + #XXX in al, dx => spot 16 bit manip; concat 66 bug + if dib_tmp != args_sample[index_im]: + log.debug("not r_cl d_dx") + good_c = False + break + + r = args_sample[index_im] + del args_sample[index_im] + dib_out.append(r) + + elif dib == mim: + if len(args_sample)<=0: + good_c = False + break + if not x86_afs.imm in args_sample[0] or not x86_afs.ad in args_sample[0] or not args_sample[0][x86_afs.ad]: + log.debug("not mim") + good_c = False + break + + for k in args_sample[0]: + if not k in [x86_afs.imm, x86_afs.ad, x86_afs.size]: + log.debug("mim: cannot encode reg ") + good_c = False + break + + a_mem = {x86_afs.size:u32, x86_afs.imm:uint32(args_sample[0][x86_afs.imm])} + opc_add.append(a_mem) + del args_sample[0] + a_pmem = dict(a_mem) + a_pmem[x86_afs.ad] = u32 + parsed_args.append(a_pmem) + + else: + raise ValueError('bad dib!!%X'%dib) + + if not good_c: + continue + + log.debug("***pass dib***") + log.debug(modifs) + + if afs in [d0, d1, d2, d3, d4, d5, d6, d7]: + if len(args_sample)!=1: + log.debug(str(c)+' bad arg num1') + continue + if args_sample[0][x86_afs.ad]: + size = args_sample[0][x86_afs.ad] + if not c.modifs[sd] == None: + size = {x86_afs.u16:x86_afs.u16, x86_afs.u32:x86_afs.u32, x86_afs.f32:x86_afs.f32, x86_afs.f64:x86_afs.f64}[size] + else: + size = args_sample[0][x86_afs.size] + if not x86mndb.check_size_modif(size, c.modifs): + log.debug(' bad size digit') + continue + + + a = dict(args_sample[-1]) + out_opc, parsed_val = x86mndb.forge_opc(out_opc, a) + if out_opc == None or parsed_val == None: + log.debug('cannot encode opc') + continue + + parsed_args.append(args_sample.pop()) + elif afs == reg: + if len(args_sample)!=1: + log.debug(str(c)+' bad arg num') + continue + if args_sample[0][x86_afs.ad]: + log.debug(' address in reg') + continue + size = args_sample[0][x86_afs.size] + if not x86mndb.check_size_modif(size, c.modifs): + log.debug(' bad size reg') + continue + + a = args_sample[-1] + k = [x for x in a.keys() if type(x) in [long, int]] + if a[x86_afs.ad] or x86_afs.imm in a or len(k)!=1: + log.debug('bad a2 %s'%str(a)) + continue + out_opc[0][-1]+=k[0] + parsed_args.append(args_sample.pop()) + + elif afs == noafs or (afs == cond and rmr in c.rm and len(args_sample)==2): + if rmr in c.rm: + if len(args_sample)!=2: + log.debug(str(c)+' bad arg num') + continue + if c.modifs[sw] and args_sample[1][x86_afs.ad]: + log.debug(' bad sw rmr 1') + continue + if not c.modifs[sw] and args_sample[0][x86_afs.ad]: + log.debug(' bad sw rmr 2') + continue + + for i in range(2): + if not args_sample[i][x86_afs.ad] and x86_afs.imm in args_sample[i]: + good_c = False + log.debug('Imm in rmr') + break + + if not good_c: + continue + + size = [] + for x in xrange(2): + size.append(args_sample[x][x86_afs.size]) + + if not (imm in dibs or ims in dibs): + if c.modifs[sw]: + size.reverse() + + if c.modifs[se]!=None: + if size[1] != [x86_afs.u08, x86_afs.u16][c.modifs[se]]: + log.debug(' bad size se rmr') + continue + elif not x86mndb.check_size_modif(size[0], c.modifs): + log.debug(' bad size rmr') + continue + + + #reg, modr + a1 = dict(args_sample[-1]) + a2 = dict(args_sample[-2]) + args_sample = args_sample[:-2] + + + + if c.modifs[sw]: + tmp_order = [a2,a1] + else: + tmp_order = [a1,a2] + + for y in mask_drcrsg: + if not modifs[y]: + continue + for x in tmp_order[1]: + if not type(x) in [int, long]: + continue + if not x&mask_drcrsg[y]: + log.debug('cr dr sg not found in reg') + good_c = False + break + tmp = tmp_order[1][x] + del(tmp_order[1][x]) + tmp_order[1][x&0xFF] = tmp + + + if not good_c: + continue + + + + out_opc, parsed_val = x86mndb.forge_opc(out_opc, *tmp_order) + if out_opc == None or parsed_val == None: + log.debug('cannot encode opc') + continue + tmp_o = [a2,a1] + if c.modifs[se] and size[0] !=size[1]: + size[1] = size[0] + if size[0] !=size[1] and name !='movzx': + if tmp_order[0][x86_afs.ad]: + size[1] = size[0] + else: + log.debug('uncompatible size in rmr') + continue + + for i in range(2): + tmp_o[-1][x86_afs.size] = size[i] + parsed_args+=tmp_o + + + elif afs == cond: + if rmr in c.rm: + if len(args_sample)!=1: + log.debug(str(c)+' bad arg num cond rmr') + continue + if args_sample[0][x86_afs.ad]: + size = args_sample[0][x86_afs.ad] + else: + size = args_sample[0][x86_afs.size] + + a = dict(args_sample[-1]) + add_out_opc, parsed_val = x86mndb.forge_opc([[0]], a) + if add_out_opc == None or parsed_val == None: + log.debug('cannot encode opc') + continue + parsed_args.append(args_sample.pop()) + out_opc[0]+=add_out_opc[0] + + + + else: + raise ValueError('erf ', afs) + + for do in dib_out: + parsed_args.append(do) + + if len(args_sample): + log.debug('too many args!') + continue + + + if self.mnemo_mode == u16: + + for a in parsed_args: + if not x86_afs.size in a: + a[x86_afs.size] = u16 + continue + if a[x86_afs.size] == u32: + a[x86_afs.size] = u16 + if a[x86_afs.ad]: + a[x86_afs.ad] = u16 + + + log.debug( "ok") + log.debug(out_opc) + log.debug(parsed_val) + log.debug(parsed_args) + for i in range(len(out_opc)): + candidate_out.append((c, parsed_args, (out_opc[i], parsed_val[i], opc_add), self.mnemo_mode)) + return prefix, candidate_out + + def _asm(self, l, symbol_off_out): + log.debug("asm: %s"%l) + prefix, candidate_out = self.asm_parse(l) + + symbol_off = [] + log.info("selected candidate for:") + log.info(l) + hex_candidate = [] + for c,eat_arg,opc_o, mnemo_mode in candidate_out: + log.info(str(c)+' '+str(eat_arg)+' '+str(opc_o)) + out_opc = prefix[:] + out_opc += opc_o[0] + val_add = [opc_o[1]]+opc_o[2] + + out_byte = reduce(lambda x,y: x+chr(y), out_opc, "") + for c in val_add: + if c == {}: + continue + if c[x86_afs.size] in [u08, s08, u16, s16, u32, s32]: + out_byte+=struct.pack(x86_afs.dict_size[c[x86_afs.size]], int(c[x86_afs.imm])) + else: + raise ValueError('bad size in asm! %s'%str(c)) + + #XXX hack for reloc gen + has_symb = None + for ea in eat_arg: + if x86_afs.ad in ea and ea[x86_afs.ad]: + has_symb = len(out_byte)-4 + symbol_off.append(has_symb) + + hex_candidate.append(out_byte) + log.info( hexdump(out_byte)) + if not len(hex_candidate): + log.warning('cannot asm %s'%str(l)) + all_candidate = zip(hex_candidate, symbol_off) + all_candidate.sort(cmp = lambda x,y:len(x[0])-len(y[0])) + hex_candidate = [x[0] for x in all_candidate] + for x in all_candidate: + symbol_off_out.append(x[1]) + + return hex_candidate + + +x86mnemo = x86_mn + +if __name__ == '__main__': + test_out = [] + log.setLevel(logging.DEBUG) + + instr = x86mnemo.dis('DB 28'.replace(' ', '').decode('hex'), admode=x86_afs.u32) + print instr + print instr.arg + print instr.l + fds + + instr = x86mnemo.dis('DB 6D 08'.replace(' ', '').decode('hex'), admode=x86_afs.u32) + print instr + print instr.arg + print instr.l + fds + + instr = x86mnemo.dis('C7 44 24 08 00 00 00 00'.replace(' ', '').decode('hex'), admode=x86_afs.u32) + print instr + print instr.arg + print instr.l + fds + + instr = x86mnemo.dis('F0 65 0F B1 0D 84 00 00 00'.replace(' ', '').decode('hex'), admode=x86_afs.u32) + print instr + print instr.arg + print instr.l + fds + + instr = x86mnemo.dis('F0 65 83 0D 84 00 00 00 10'.replace(' ', '').decode('hex'), admode=x86_afs.u32) + print instr + print instr.arg + print instr.l + fds + + instr = x86mnemo.dis('65 C7 05 28 02 00 00 FF FF FF FF'.replace(' ', '').decode('hex'), admode=x86_afs.u32) + print instr + print instr.arg + fds + + instr = x86mnemo.dis('66ab'.decode('hex'), admode=x86_afs.u32) + print instr + print instr.arg + fds + + instr = x86mnemo.dis('6681384D5A0000'.decode('hex'), admode=x86_afs.u32) + print instr + print instr.arg diff --git a/miasm/arch/ia32_reg.py b/miasm/arch/ia32_reg.py new file mode 100644 index 00000000..9c49691e --- /dev/null +++ b/miasm/arch/ia32_reg.py @@ -0,0 +1,159 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +class afs_desc: + def __init__(self): + + self.noad = "no_ad" + self.ad = "ad" + + self.ad8 = "ad8" + self.ad16 = "ad16" + self.ad32 = "ad32" + self.segm = "segm" + + self.size = "size" + + self.symb = "symb__intern__" + + self.imm = "imm" + self.s08 = "s08" + self.u08 = "u08" + self.u16 = "u16" + self.s16 = "s16" + self.u32 = "u32" + self.s32 = "s32" + self.s32 = "s32" + + self.f32 = "f32" + self.f64 = "f64" + self.fpu = "fpu" + + self.im1 = "im1" + self.im3 = "im3" + self.ims = "ims" + self.mim = "mim" + + self.size_seg = "size_seg" + + self.dict_size = {self.imm:'imm', + self.s08:'b', + self.u08:'B', + self.s16:'h', + self.u16:'H', + self.s32:'i', + self.u32:'I', + } + + + + self.r_eax = "eax" + self.r_ecx = "ecx" + self.r_edx = "edx" + self.r_ebx = "ebx" + self.r_esp = "esp" + self.r_ebp = "ebp" + self.r_esi = "esi" + self.r_edi = "edi" + + self.r_dr0 = "dr0" + self.r_dr1 = "dr1" + self.r_dr2 = "dr2" + self.r_dr3 = "dr3" + self.r_dr4 = "dr4" + self.r_dr5 = "dr5" + self.r_dr6 = "dr6" + self.r_dr7 = "dr7" + + self.r_cr0 = "cr0" + self.r_cr1 = "cr1" + self.r_cr2 = "cr2" + self.r_cr3 = "cr3" + self.r_cr4 = "cr4" + self.r_cr5 = "cr5" + self.r_cr6 = "cr6" + self.r_cr7 = "cr7" + + self.r_ax = "ax" + self.r_cx = "cx" + self.r_dx = "dx" + self.r_bx = "bx" + self.r_sp = "sp" + self.r_bp = "bp" + self.r_si = "si" + self.r_di = "di" + + self.r_al = "al" + self.r_cl = "cl" + self.r_dl = "dl" + self.r_bl = "bl" + self.r_ah = "ah" + self.r_ch = "ch" + self.r_dh = "dh" + self.r_bh = "bh" + + + self.r_es = "es" + self.r_cs = "cs" + self.r_ss = "ss" + self.r_ds = "ds" + self.r_fs = "fs" + self.r_gs = "gs" + + self.reg_list8 =[self.r_al, self.r_cl, self.r_dl, self.r_bl, + self.r_ah, self.r_ch, self.r_dh, self.r_bh] + self.reg_list16=[self.r_ax, self.r_cx, self.r_dx, self.r_bx, + self.r_sp, self.r_bp, self.r_si, self.r_di] + self.reg_list32=[self.r_eax, self.r_ecx, self.r_edx, self.r_ebx, + self.r_esp, self.r_ebp, self.r_esi, self.r_edi] + + self.reg_dr= [self.r_dr0, self.r_dr1, self.r_dr2, self.r_dr3, + self.r_dr4, self.r_dr5, self.r_dr6, self.r_dr7] + + self.reg_cr= [self.r_cr0, self.r_cr1, self.r_cr2, self.r_cr3, + self.r_cr4, self.r_cr5, self.r_cr6, self.r_cr7] + + self.reg_sg= [self.r_es, self.r_cs, self.r_ss, self.r_ds, + self.r_fs, self.r_gs, None, None] + + self.reg_flt = ["st%d"%i for i in range(8)] + + self.reg_dict = {} + for i in range(8): + self.reg_dict[self.reg_list8[i]] = i + for i in range(8): + self.reg_dict[self.reg_list16[i]] = i + for i in range(8): + self.reg_dict[self.reg_list32[i]] = i + for i in range(8): + self.reg_dict[self.reg_flt[i]] = i + for i in range(8): + self.reg_dict[self.reg_cr[i]] = i+0x100 + for i in range(8): + self.reg_dict[self.reg_dr[i]] = i+0x200 + for i in range(8): + self.reg_dict[self.reg_sg[i]] = i+0x400 + + + + self.x86_prefix = [0xF0, 0xF2, 0xF3, + 0x2E, 0x36, 0x3E, 0x26, 0x64, 0x65, + 0x66, + 0x67] + + +x86_afs = afs_desc() diff --git a/miasm/arch/ia32_sem.py b/miasm/arch/ia32_sem.py new file mode 100644 index 00000000..013c0f31 --- /dev/null +++ b/miasm/arch/ia32_sem.py @@ -0,0 +1,2136 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from miasm.expression.expression import * +from miasm.arch.ia32_reg import * +from miasm.arch.ia32_arch import * + + +EXCEPT_PRIV_INSN = 1<<7 +reg_eax = 'eax' +reg_ebx = 'ebx' +reg_ecx = 'ecx' +reg_edx = 'edx' +reg_esp = 'esp' +reg_ebp = 'ebp' +reg_eip = 'eip' +reg_esi = 'esi' +reg_edi = 'edi' +reg_eflag = 'eflag' +reg_tmp1 = 'tmp1' + +reg_zf = 'zf' +reg_nf = 'nf' +reg_pf = 'pf' +reg_of = 'of' +reg_cf = 'cf' +reg_tf = 'tf' +reg_if = 'i_f' +reg_df = 'df' +reg_af = 'af' +reg_iopl='iopl_f' +reg_nt = 'nt' +reg_rf = 'rf' +reg_vm = 'vm' +reg_ac = 'ac' +reg_vif= 'vif' +reg_vip= 'vip' +reg_id = 'i_d' + + +reg_es = "es" +reg_cs = "cs" +reg_ss = "ss" +reg_ds = "ds" +reg_fs = "fs" +reg_gs = "gs" + +reg_dr0 = 'dr0' +reg_dr1 = 'dr1' +reg_dr2 = 'dr2' +reg_dr3 = 'dr3' +reg_dr4 = 'dr4' +reg_dr5 = 'dr5' +reg_dr6 = 'dr6' +reg_dr7 = 'dr7' + +reg_cr0 = 'cr0' +reg_cr1 = 'cr1' +reg_cr2 = 'cr2' +reg_cr3 = 'cr3' +reg_cr4 = 'cr4' +reg_cr5 = 'cr5' +reg_cr6 = 'cr6' +reg_cr7 = 'cr7' + + +reg_tsc1 = "tsc1" +reg_tsc2 = "tsc2" + +reg_float_c0 = 'float_c0' +reg_float_c1 = 'float_c1' +reg_float_c2 = 'float_c2' +reg_float_c3 = 'float_c3' +reg_float_stack_ptr = "float_stack_ptr" +reg_float_control = 'reg_float_control' + + +reg_float_st0 = 'float_st0' +reg_float_st1 = 'float_st1' +reg_float_st2 = 'float_st2' +reg_float_st3 = 'float_st3' +reg_float_st4 = 'float_st4' +reg_float_st5 = 'float_st5' +reg_float_st6 = 'float_st6' +reg_float_st7 = 'float_st7' + + + +#commonly used +init_eax = ExprId("init_eax", is_term=True) +init_ebx = ExprId("init_ebx", is_term=True) +init_ecx = ExprId("init_ecx", is_term=True) +init_edx = ExprId("init_edx", is_term=True) +init_esi = ExprId("init_esi", is_term=True) +init_edi = ExprId("init_edi", is_term=True) +init_esp = ExprId("init_esp", is_term=True) +init_ebp = ExprId("init_ebp", is_term=True) + + + + +init_tsc1 = ExprId("init_tsc1") +init_tsc2 = ExprId("init_tsc2") + +init_cr0 = ExprId("init_cr0") + + +init_zf = ExprId("init_zf") +init_nf = ExprId("init_nf") +init_pf = ExprId("init_pf") +init_of = ExprId("init_of") +init_cf = ExprId("init_cf") +init_tf = ExprId("init_tf") +init_i_f = ExprId("init_i_f") +init_df = ExprId("init_df") +init_af = ExprId("init_af") +init_iopl = ExprId("init_iopl") +init_nt = ExprId("init_nt") +init_rf = ExprId("init_rf") +init_vm = ExprId("init_vm") +init_ac = ExprId("init_ac") +init_vif = ExprId("init_vif") +init_vip = ExprId("init_vip") +init_i_d = ExprId("init_i_d") +init_tsc1 = ExprId("init_tsc1") +init_tsc2 = ExprId("init_tsc2") + + + +eax = ExprId(reg_eax) +ebx = ExprId(reg_ebx) +ecx = ExprId(reg_ecx) +edx = ExprId(reg_edx) +esp = ExprId(reg_esp) +ebp = ExprId(reg_ebp) +eip = ExprId(reg_eip) +esi = ExprId(reg_esi) +edi = ExprId(reg_edi) + + +r_al = eax[:8] +r_cl = ecx[:8] +r_dl = edx[:8] +r_bl = ebx[:8] +r_ah = eax[8:16] +r_ch = ecx[8:16] +r_dh = edx[8:16] +r_bh = ebx[8:16] + +r_ax = eax[:16] +r_bx = ebx[:16] +r_cx = ecx[:16] +r_dx = edx[:16] +r_sp = esp[:16] +r_bp = ebp[:16] +r_ip = eip[:16] +r_si = esi[:16] +r_di = edi[:16] + + +dr0 = ExprId(reg_dr0) +dr1 = ExprId(reg_dr1) +dr2 = ExprId(reg_dr2) +dr3 = ExprId(reg_dr3) +dr4 = ExprId(reg_dr4) +dr5 = ExprId(reg_dr5) +dr6 = ExprId(reg_dr6) +dr7 = ExprId(reg_dr7) + +cr0 = ExprId(reg_cr0) +cr1 = ExprId(reg_cr1) +cr2 = ExprId(reg_cr2) +cr3 = ExprId(reg_cr3) +cr4 = ExprId(reg_cr4) +cr5 = ExprId(reg_cr5) +cr6 = ExprId(reg_cr6) +cr7 = ExprId(reg_cr7) + + +eflag= ExprId(reg_eflag) +tmp1= ExprId(reg_tmp1) +zf = ExprId(reg_zf, size=1) +nf = ExprId(reg_nf, size=1) +pf = ExprId(reg_pf, size=1) +of = ExprId(reg_of, size=1) +cf = ExprId(reg_cf, size=1) +tf = ExprId(reg_tf , size=1) +i_f= ExprId(reg_if , size=1) +df = ExprId(reg_df , size=1) +af = ExprId(reg_af , size=1) +iopl=ExprId(reg_iopl,size=2) +nt = ExprId(reg_nt , size=1) +rf = ExprId(reg_rf , size=1) +vm = ExprId(reg_vm , size=1) +ac = ExprId(reg_ac , size=1) +vif= ExprId(reg_vif, size=1) +vip= ExprId(reg_vip, size=1) +i_d= ExprId(reg_id , size=1) + +es = ExprId(reg_es, size = 16) +cs = ExprId(reg_cs, size = 16) +ss = ExprId(reg_ss, size = 16) +ds = ExprId(reg_ds, size = 16) +fs = ExprId(reg_fs, size = 16) +gs = ExprId(reg_gs, size = 16) + +tsc1 = ExprId(reg_tsc1, size = 32) +tsc2 = ExprId(reg_tsc2, size = 32) + +float_c0 = ExprId(reg_float_c0) +float_c1 = ExprId(reg_float_c1) +float_c2 = ExprId(reg_float_c2) +float_c3 = ExprId(reg_float_c3) +float_stack_ptr = ExprId(reg_float_stack_ptr) +float_control = ExprId(reg_float_control) + +float_st0 = ExprId(reg_float_st0) +float_st1 = ExprId(reg_float_st1) +float_st2 = ExprId(reg_float_st2) +float_st3 = ExprId(reg_float_st3) +float_st4 = ExprId(reg_float_st4) +float_st5 = ExprId(reg_float_st5) +float_st6 = ExprId(reg_float_st6) +float_st7 = ExprId(reg_float_st7) + + + +init_regs = { +eax:init_eax, +ebx:init_ebx, +ecx:init_ecx, +edx:init_edx, +esi:init_esi, +edi:init_edi, +esp:init_esp, +ebp:init_ebp, +zf:init_zf, +nf:init_nf, +pf:init_pf, +of:init_of, +cf:init_cf, +tf:init_tf, +i_f:init_i_f, +df:init_df, +af:init_af, +iopl:init_iopl, +nt:init_nt, +rf:init_rf, +vm:init_vm, +ac:init_ac, +vif:init_vif, +vip:init_vip, +i_d:init_i_d, +tsc1:init_tsc1, +tsc2:init_tsc2, +} + +all_registers = [ + eax , + ebx , + ecx , + edx , + esp , + ebp , + eip , + esi , + edi , + dr0, + dr1, + dr2, + dr3, + dr4, + dr5, + dr6, + dr7, + + eflag, + tmp1, + zf , + nf , + pf , + of , + cf , + tf , + i_f, + df , + af , + iopl, + nt , + rf , + vm , + ac , + vif, + vip, + i_d, + + es , + cs , + ss , + ds , + fs , + gs , + + tsc1 , + tsc2 , + + float_c0 , + float_c1 , + float_c2 , + float_c3 , + float_stack_ptr , + float_control , + + float_st0 , + float_st1 , + float_st2 , + float_st3 , + float_st4 , + float_st5 , + float_st6 , + float_st7 , + + ] + +tab_intsize = {8:int8, + 16:int16, + 32:int32, + 64:int64 + } +tab_uintsize ={8:uint8, + 16:uint16, + 32:uint32, + 64:uint64 + } + +tab_afs_int ={x86_afs.u08:uint8, + x86_afs.u16:uint16, + x86_afs.u32:uint32, + } +""" +http://www.emulators.com/docs/nx11_flags.htm + +CF(A+B) = (((A XOR B) XOR D) < 0) XOR (((A XOR D) AND NOT (A XOR B)) < 0) +CF(A-B) = (((A XOR B) XOR D) < 0) XOR (((A XOR D) AND (A XOR B)) < 0) + +OF(A+B) = ((A XOR D) AND NOT (A XOR B)) < 0 +OF(A-B) = ((A XOR D) AND (A XOR B)) < 0 +""" + +def get_op_msb(a): + cast_int = tab_uintsize[a.get_size()] + return ExprOp('==', ExprInt(cast_int(1)), ExprOp('>>', a, ExprInt(cast_int(a.get_size()-1)))) + + +def update_flag_zf(a): + cast_int = tab_uintsize[a.get_size()] + return [ExprAff(zf, ExprOp('==', a, ExprInt(cast_int(0))))] + +def update_flag_nf(a): + return [ExprAff(nf, ExprOp('&', get_op_msb(a), ExprInt(tab_uintsize[a.get_size()](1))))] + +def update_flag_pf(a): + return [ExprAff(pf, ExprOp('parity', a))] + +def update_flag_af(a): + return [ExprAff(af, ExprOp('==', ExprOp('&', a, ExprInt(tab_uintsize[a.get_size()](0x10))), ExprInt(tab_uintsize[a.get_size()](0x10))))] + +def update_flag_znp(a): + e = [] + e+=update_flag_zf(a) + e+=update_flag_nf(a) + e+=update_flag_pf(a) + return e + +def update_flag_logic(a): + e = [] + e+=update_flag_znp(a) + e.append(ExprAff(of, ExprInt(uint32(0)))) + e.append(ExprAff(cf, ExprInt(uint32(0)))) + return e + +def update_flag_arith(a): + e = [] + e+=update_flag_znp(a) + return e + + +def check_ops_msb(a, b, c): + if not a or not b or not c or a!=b or a!=c: + raise 'bad ops size %s %s %s'%(str(a), str(b), str(c)) + +def arith_flag(a, b, c): + a_s, b_s, c_s = a.get_size(), b.get_size(), c.get_size() + check_ops_msb(a_s, b_s, c_s) + a_s, b_s, c_s = get_op_msb(a), get_op_msb(b), get_op_msb(c) + return a_s, b_s, c_s + + +#checked: ok for adc add because of b & c before +cf +def update_flag_add_cf(cast_int, a, b, c): + return ExprAff(cf, get_op_msb((a ^ b) ^ c) ^ get_op_msb((a ^ c) & ExprOp('!', (a ^ b)))) + +def update_flag_add_of(cast_int, a, b, c): + return ExprAff(of, get_op_msb(((a ^ c) & ExprOp('!', (a ^ b))))) + + + +#checked: ok for sbb add because of b & c before +cf +def update_flag_sub_cf(cast_int, a, b, c): + return ExprAff(cf, get_op_msb((a ^ b) ^ c) ^ get_op_msb((a ^ c) & (a ^ b))) + + +def update_flag_sub_of(cast_int, a, b, c): + return ExprAff(of, get_op_msb(((a ^ c) & (a ^ b)))) + + + + + +#z = x+y (+cf?) +def update_flag_add(x, y, z): + cast_int = tab_uintsize[z.get_size()] + e = [] + e.append(update_flag_add_cf(cast_int, x, y, z)) + e.append(update_flag_add_of(cast_int, x, y, z)) + return e + +#z = x-y (+cf?) +def update_flag_sub(x, y, z): + cast_int = tab_uintsize[z.get_size()] + e = [] + e.append(update_flag_sub_cf(cast_int, x, y, z)) + e.append(update_flag_sub_of(cast_int, x, y, z)) + return e + + +def mov(a, b): + return [ExprAff(a, b)] + +def xchg(a, b): + e = [] + e.append(ExprAff(a, b)) + e.append(ExprAff(b, a)) + return e + +def movzx(a, b): + return [ExprAff(a, ExprCompose([ExprSliceTo(ExprInt(uint32(0)), b.get_size(), a.get_size()), ExprSliceTo(b, 0, b.get_size())]))] + +def movsx(a, b): + return [ExprAff(a, ExprCompose([ExprSliceTo(ExprCond(ExprOp('==', get_op_msb(b), ExprInt(uint32(1))), + ExprInt(uint32(0xffffffff)), + ExprInt(uint32(0))), + b.get_size(), a.get_size()), + ExprSliceTo(b, + 0, b.get_size())]))] + +def lea(a, b): + return [ExprAff(a, b.arg)] + +def add(a, b): + e= [] + c = ExprOp('+', a, b) + e+=update_flag_arith(c) + e+=update_flag_af(c) + e+=update_flag_add(a, b, c) + e.append(ExprAff(a, c)) + return e + +def xadd(a, b): + e= [] + c = ExprOp('+', b, a) + e+=update_flag_arith(c) + e+=update_flag_af(c) + e+=update_flag_add(b, a, c) + e.append(ExprAff(b, a)) + e.append(ExprAff(a, c)) + return e + +def adc(a, b): + e= [] + c = ExprOp('+', + a, + ExprOp('+', + b, + ExprCompose([ExprSliceTo(ExprInt(uint32(0)), 1, a.get_size()), ExprSliceTo(cf, 0, 1)]))) + e+=update_flag_arith(c) + e+=update_flag_af(c) + e+=update_flag_add(a, b, c) + e.append(ExprAff(a, c)) + return e + +def sub(a, b): + e= [] + c = ExprOp('-', a, b) + e+=update_flag_arith(c) + e+=update_flag_af(c) + e+=update_flag_sub(a, b, c) + e.append(ExprAff(a, c)) + return e + +#a-(b+cf) +def sbb(a, b): + e= [] + c = ExprOp('-', + a, + ExprOp('+', + b, + ExprCompose([ExprSliceTo(ExprInt(uint32(0)), 1, a.get_size()), ExprSliceTo(cf, 0, 1)]))) + e+=update_flag_arith(c) + e+=update_flag_af(c) + e+=update_flag_sub(a, b, c) + e.append(ExprAff(a, c)) + return e + +def neg(b): + e= [] + cast_int = tab_uintsize[b.get_size()] + a = ExprInt(cast_int(0)) + + c = ExprOp('-', a, b) + e+=update_flag_arith(c) + e+=update_flag_sub(a, b, c) + e+=update_flag_af(c) + e.append(ExprAff(b, c)) + return e + +def l_not(b): + e= [] + cast_int = tab_uintsize[b.get_size()] + c = ExprOp('!', b) + e.append(ExprAff(b, c)) + return e + + +def l_cmp(a, b): + e= [] + c = ExprOp('-', a, b) + e+=update_flag_arith(c) + e+=update_flag_sub(a, b, c) + e+=update_flag_af(c) + return e + +def xor(a, b): + e= [] + c = ExprOp('^', a, b) + e+=update_flag_logic(c) + e.append(ExprAff(a, c)) + return e + +def l_or(a, b): + e= [] + c = ExprOp('|', a, b) + e+=update_flag_logic(c) + e.append(ExprAff(a, c)) + return e + +def l_and(a, b): + e= [] + c = ExprOp('&', a, b) + e+=update_flag_logic(c) + e.append(ExprAff(a, c)) + return e + +def l_test(a, b): + e= [] + c = ExprOp('&', a, b) + e+=update_flag_logic(c) + return e + +def l_rol(a, b): + e= [] + cast_int = tab_uintsize[a.get_size()] + c = ExprOp('<<<', a, b) + + new_cf = ExprOp("&", c ,ExprInt(cast_int(1))) + e.append(ExprAff(cf, new_cf)) + ### hack (only valid if b=1) + e.append(ExprAff(of, ExprOp("^", get_op_msb(c), new_cf))) + e.append(ExprAff(a, c)) + return e + +def l_ror(a, b): + e= [] + c = ExprOp('>>>', a, b) + + e.append(ExprAff(cf, get_op_msb(c))) + ### hack (only valid if b=1): when count == 1: a = msb-1(dest) + e.append(ExprAff(of, ExprOp("^", get_op_msb(c), get_op_msb(a)))) + e.append(ExprAff(a, c)) + return e + +def rcl(a, b): + e= [] + c = ExprOp('<<<c_rez', a, b, cf) + new_cf = ExprOp('<<<c_cf', a, b, cf) + + e.append(ExprAff(cf, new_cf)) + ### hack (only valid if b=1) + e.append(ExprAff(of, ExprOp("^", get_op_msb(c), new_cf))) + e.append(ExprAff(a, c)) + return e + +def rcr(a, b): + e= [] + c = ExprOp('>>>c_rez', a, b, cf) + new_cf = ExprOp('>>>c_cf', a, b, cf) + + e.append(ExprAff(cf, new_cf)) + ### hack (only valid if b=1) + e.append(ExprAff(of, ExprOp("^", get_op_msb(a), get_op_msb(c)))) + e.append(ExprAff(a, c)) + + return e + +def sar(a, b): + e= [] + cast_int = tab_uintsize[a.get_size()] + cast_intb = tab_uintsize[b.get_size()] + + shifter = ExprOp('&',b, ExprInt(cast_intb(0x1f))) + c = ExprOp('a>>', a, shifter) + + new_cf = ExprOp('&', + ExprInt(cast_int(1)), + ExprOp('a>>', + a, + ExprOp('-', + shifter, + ExprInt(cast_intb(1)) + ) + + ) + ) + + e.append(ExprAff(cf, ExprCond(shifter, + new_cf, + cf) + ) + ) + e.append(ExprAff(of, ExprInt(cast_int(0)))) + e+=update_flag_znp(c) + e.append(ExprAff(a, c)) + return e + +def shr(a, b): + e= [] + cast_int = tab_uintsize[a.get_size()] + cast_intb = tab_uintsize[b.get_size()] + shifter = ExprOp('&',b, ExprInt(cast_intb(0x1f))) + c = ExprOp('>>', a, shifter) + + new_cf = ExprOp('&', + ExprInt(cast_int(1)), + ExprOp('>>', + a, + ExprOp('-', + shifter, + ExprInt(cast_intb(1)) + ) + + ) + ) + + e.append(ExprAff(cf, ExprCond(shifter, + new_cf, + cf) + ) + ) + + e.append(ExprAff(of, get_op_msb(a))) + e+=update_flag_znp(c) + e.append(ExprAff(a, c)) + return e + +def shrd_cl(a, b): + e= [] + cast_int = tab_uintsize[a.get_size()] + cast_intb = tab_uintsize[b.get_size()] + + shifter = ExprOp('&',ecx, ExprInt(cast_intb(0x1f))) + + c = ExprOp('|', + ExprOp('>>', a, shifter), + ExprOp('<<', b, ExprOp('-', + ExprInt(cast_int(a.get_size())), + shifter) + ) + ) + + new_cf = ExprOp('&', + ExprInt(cast_int(1)), + ExprOp('>>', + a, + ExprOp('-', + shifter, + ExprInt(cast_intb(1)) + ) + + ) + ) + e.append(ExprAff(cf, ExprCond(shifter, + new_cf, + cf) + ) + ) + e.append(ExprAff(of, get_op_msb(a))) + e+=update_flag_znp(c) + e.append(ExprAff(a, c)) + return e + +def shrd(a, b, c): + e= [] + cast_int = tab_uintsize[a.get_size()] + cast_intb = tab_uintsize[b.get_size()] + + shifter = c + + d = ExprOp('|', + ExprOp('>>', a, shifter), + ExprOp('<<', b, ExprOp('-', + ExprInt(cast_int(a.get_size())), + shifter) + ) + ) + + new_cf = ExprAff(cf, ExprOp('&', + ExprInt(cast_int(1)), + ExprOp('>>', + a, + ExprOp('-', + shifter, + ExprInt(cast_intb(1)) + ) + ) + ) + ) + e.append(ExprAff(cf, ExprCond(shifter, + new_cf, + cf) + ) + ) + e.append(ExprAff(of, get_op_msb(a))) + e+=update_flag_znp(d) + e.append(ExprAff(a, d)) + return e + +def sal(a, b): + e= [] + cast_int = tab_uintsize[a.get_size()] + cast_intb = tab_uintsize[b.get_size()] + shifter = ExprOp('&',b, ExprInt(cast_intb(0x1f))) + + c = ExprOp('a<<', a, shifter) + new_cf = ExprOp('&', + ExprInt(cast_int(1)), + ExprOp('>>', + a, + ExprOp('-', + ExprInt(cast_intb(a.get_size())), + shifter + ) + + ) + ) + + e.append(ExprAff(cf, ExprCond(shifter, + new_cf, + cf) + ) + ) + e+=update_flag_znp(c) + e.append(ExprAff(of, ExprOp('^', get_op_msb(c), new_cf))) + e.append(ExprAff(a, c)) + return e + +def shl(a, b): + e= [] + cast_int = tab_uintsize[a.get_size()] + cast_intb = tab_uintsize[b.get_size()] + shifter = ExprOp('&',b, ExprInt(cast_intb(0x1f))) + + c = ExprOp('<<', a, shifter) + new_cf = ExprOp('&', + ExprInt(cast_int(1)), + ExprOp('>>', + a, + ExprOp('-', + ExprInt(cast_intb(a.get_size())), + shifter + ) + + ) + ) + e.append(ExprAff(cf, ExprCond(shifter, + new_cf, + cf) + ) + ) + e+=update_flag_znp(c) + e.append(ExprAff(of, ExprOp('^', get_op_msb(c), new_cf))) + e.append(ExprAff(a, c)) + return e + +def shld_cl(a, b): + e= [] + cast_int = tab_uintsize[a.get_size()] + cast_intb = tab_uintsize[b.get_size()] + shifter = ExprOp('&',ecx, ExprInt(cast_int(0x1f))) + + c = ExprOp('|', + ExprOp('<<', a, shifter), + ExprOp('>>', b, ExprOp('-', + ExprInt(cast_int(a.get_size())), + shifter) + ) + ) + + new_cf = ExprOp('&', + ExprInt(cast_int(1)), + ExprOp('>>', + a, + ExprOp('-', + ExprInt(cast_intb(a.get_size())), + shifter + ) + + ) + ) + e.append(ExprAff(cf, ExprCond(shifter, + new_cf, + cf) + ) + ) + e+=update_flag_znp(c) + e.append(ExprAff(of, ExprOp('^', get_op_msb(c), new_cf))) + e.append(ExprAff(a, c)) + return e + + +#XXX todo ### +def cmc(): + return [ExprAff(cf, ExprOp('==', cf, ExprInt(uint32(0))))] + +def clc(): + return [ExprAff(cf, ExprInt(uint32(0)))] + +def stc(): + return [ExprAff(cf, ExprInt(uint32(1)))] + +def cld(): + return [ExprAff(df, ExprInt(uint32(0)))] + +def std(): + return [ExprAff(df, ExprInt(uint32(1)))] + +def cli(): + return [ExprAff(i_f, ExprInt(uint32(0)))] + +def sti(): + return [ExprAff(ExprId('vmcpu.vm_exception_flags'), ExprInt(uint32(1<<7)))] + +def inc(a): + e= [] + b = ExprInt(tab_uintsize[a.get_size()](1)) + c = ExprOp('+', a, b) + e+=update_flag_arith(c) + e+=update_flag_af(c) + + cast_int = tab_uintsize[c.get_size()] + e.append(update_flag_add_of(cast_int, a, b, c)) + e.append(ExprAff(a, c)) + return e + + +def dec(a): + e= [] + b = ExprInt(tab_uintsize[a.get_size()](-1)) + c = ExprOp('+', a, b) + e+=update_flag_arith(c) + e+=update_flag_af(c) + + cast_int = tab_uintsize[c.get_size()] + e.append(update_flag_add_of(cast_int, a, b, c)) + e.append(ExprAff(a, c)) + return e + +def push(a): + e= [] + s = a.get_size() + if not s in [16,32]: + raise 'bad size stacker!' + c = ExprOp('-', esp, ExprInt(uint32(s/8))) + e.append(ExprAff(esp, c)) + e.append(ExprAff(ExprMem(c, s), a)) + return e + +def pop(a): + e= [] + s = a.get_size() + if not s in [16,32]: + raise 'bad size stacker!' + new_esp = ExprOp('+', esp, ExprInt(uint32(s/8))) + e.append(ExprAff(esp, new_esp)) + #XXX FIX XXX for pop [esp] + if isinstance(a, ExprMem): + a =a.reload_expr({esp:new_esp}) + e.append(ExprAff(a, ExprMem(esp, s))) + return e + +def sete(a): + e = [] + e.append(ExprAff(a, ExprCond(ExprOp('==', zf, ExprInt(uint32(1))), ExprInt(tab_uintsize[a.get_size()](1)), ExprInt(tab_uintsize[a.get_size()](0))))) + return e + +def setnz(a): + e = [] + e.append(ExprAff(a, ExprCond(ExprOp('==', zf, ExprInt(uint32(0))), ExprInt(tab_uintsize[a.get_size()](1)), ExprInt(tab_uintsize[a.get_size()](0))))) + return e + +def setl(a): + e = [] + e.append(ExprAff(a, ExprCond(ExprOp('==', ExprOp('==', nf, of), ExprInt(uint32(0))), ExprInt(tab_uintsize[a.get_size()](1)), ExprInt(tab_uintsize[a.get_size()](0))))) + return e + +def setg(a): + e = [] + e.append(ExprAff(a, ExprCond(ExprOp("&", ExprOp('==', zf, ExprInt(uint32(0))), ExprOp('==', nf, of)), ExprInt(tab_uintsize[a.get_size()](1)), ExprInt(tab_uintsize[a.get_size()](0))))) + return e + +def setge(a): + e = [] + e.append(ExprAff(a, ExprCond(ExprOp('==', nf, of), ExprInt(tab_uintsize[a.get_size()](1)), ExprInt(tab_uintsize[a.get_size()](0))))) + return e + + +def seta(a): + e = [] + e.append(ExprAff(a, ExprCond(ExprOp('&', ExprOp('==', cf, ExprInt(uint32(0))), ExprOp('==', zf, ExprInt(uint32(0)))), ExprInt(tab_uintsize[a.get_size()](1)), ExprInt(tab_uintsize[a.get_size()](0))))) + return e + +def setb(a): + e = [] + e.append(ExprAff(a, ExprCond(ExprOp('==', cf, ExprInt(uint32(1))), ExprInt(tab_uintsize[a.get_size()](1)), ExprInt(tab_uintsize[a.get_size()](0))))) + return e + +def setns(a): + e = [] + e.append(ExprAff(a, ExprCond(ExprOp('==', nf, ExprInt(uint32(0))), ExprInt(tab_uintsize[a.get_size()](1)), ExprInt(tab_uintsize[a.get_size()](0))))) + return e + +def sets(a): + e = [] + e.append(ExprAff(a, ExprCond(ExprOp('==', nf, ExprInt(uint32(1))), ExprInt(tab_uintsize[a.get_size()](1)), ExprInt(tab_uintsize[a.get_size()](0))))) + return e + + +def seto(a): + e= [] + e.append(ExprAff(a, ExprCond(ExprOp('==', of, ExprInt(uint32(1))), ExprInt(tab_uintsize[a.get_size()](1)), ExprInt(tab_uintsize[a.get_size()](0))))) + return e + + +def bswap(a): + e = [] + c = ExprCompose([ExprSliceTo(ExprOp('&', ExprInt(tab_uintsize[a.get_size()](0xFF)), a), 24, 32), + ExprSliceTo(ExprOp('>>', ExprOp('&', ExprInt(tab_uintsize[a.get_size()](0xFF00)), a), ExprInt(uint32(8))), 16, 24), + ExprSliceTo(ExprOp('>>', ExprOp('&', ExprInt(tab_uintsize[a.get_size()](0xFF0000)), a), ExprInt(uint32(16))), 8 , 16), + ExprSliceTo(ExprOp('>>', ExprOp('&', ExprInt(tab_uintsize[a.get_size()](0xFF000000)), a), ExprInt(uint32(24))),0 , 8 ), + ]) + e.append(ExprAff(a, c)) + return e + +def cmpsb(): + e= [] + e+=l_cmp(ExprMem(esi, 8), ExprMem(edi, 8)) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(1))), ExprOp('+', edi, ExprInt(uint32(1)))))) + e.append(ExprAff(esi, ExprCond(df, ExprOp('-', esi, ExprInt(uint32(1))), ExprOp('+', esi, ExprInt(uint32(1)))))) + return e + +def cmpsw(): + e= [] + e+=l_cmp(ExprMem(esi, 16), ExprMem(edi, 16)) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(2))), ExprOp('+', edi, ExprInt(uint32(2)))))) + e.append(ExprAff(esi, ExprCond(df, ExprOp('-', esi, ExprInt(uint32(2))), ExprOp('+', esi, ExprInt(uint32(2)))))) + return e + +def cmpsd(): + e= [] + e+=l_cmp(ExprMem(esi), ExprMem(edi)) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(4))), ExprOp('+', edi, ExprInt(uint32(4)))))) + e.append(ExprAff(esi, ExprCond(df, ExprOp('-', esi, ExprInt(uint32(4))), ExprOp('+', esi, ExprInt(uint32(4)))))) + return e + +def scasb(): + e= [] + e+=l_cmp(eax[0:8], ExprMem(edi, 8)) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(1))), ExprOp('+', edi, ExprInt(uint32(1)))))) + return e + +def scasw(): + e= [] + e+=l_cmp(eax[0:16], ExprMem(edi, 16)) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(2))), ExprOp('+', edi, ExprInt(uint32(2)))))) + return e + +def scasd(): + e= [] + e+=l_cmp(eax, ExprMem(edi)) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(4))), ExprOp('+', edi, ExprInt(uint32(4)))))) + return e + + +def compose_eflag(s = 32): + args = [] + + regs = [cf, ExprInt(uint32(1)), pf, ExprInt(uint32(0)), af, ExprInt(uint32(0)), zf, nf, tf, i_f, df, of] + for i in xrange(len(regs)): + args.append(ExprSliceTo(regs[i],i, i+1)) + + args.append(ExprSliceTo(iopl,12, 14)) + + if s == 32: + regs = [nt, ExprInt(uint32(0)), rf, vm, ac, vif, vip, i_d] + elif s == 16: + regs = [nt, ExprInt(uint32(0))] + else: + fdsfsdf + for i in xrange(len(regs)): + args.append(ExprSliceTo(regs[i],i+14, i+15)) + if s == 32: + args.append(ExprSliceTo(ExprInt(uint32(0)),22, 32)) + + return ExprCompose(args) + + + +def pushfd(): + return push(compose_eflag()) + +def pushfw(): + return push(compose_eflag(16)) + +def popfd(): + tmp = ExprMem(esp) + e = [] + e.append(ExprAff(cf, ExprSlice(tmp, 0, 1))) + e.append(ExprAff(pf, ExprSlice(tmp, 2, 3))) + e.append(ExprAff(af, ExprSlice(tmp, 4, 5))) + e.append(ExprAff(zf, ExprSlice(tmp, 6, 7))) + e.append(ExprAff(nf, ExprSlice(tmp, 7, 8))) + e.append(ExprAff(tf, ExprSlice(tmp, 8, 9))) + e.append(ExprAff(i_f,ExprSlice(tmp, 9, 10))) + e.append(ExprAff(df, ExprSlice(tmp, 10, 11))) + e.append(ExprAff(of, ExprSlice(tmp, 11, 12))) + e.append(ExprAff(iopl, ExprSlice(tmp, 12, 14))) + e.append(ExprAff(nt, ExprSlice(tmp, 14, 15))) + e.append(ExprAff(rf, ExprSlice(tmp, 16, 17))) + e.append(ExprAff(vm, ExprSlice(tmp, 17, 18))) + e.append(ExprAff(ac, ExprSlice(tmp, 18, 19))) + e.append(ExprAff(vif,ExprSlice(tmp, 19, 20))) + e.append(ExprAff(vip,ExprSlice(tmp, 20, 21))) + e.append(ExprAff(i_d,ExprSlice(tmp, 21, 22))) + e.append(ExprAff(esp, ExprOp('+', esp, ExprInt(uint32(4))))) + + return e + +def pushad(): + e = [] + s = 32 + if not s in [16,32]: + raise 'bad size stacker!' + + regs = [eax, ecx, edx, ebx, esp, ebp, esi, edi] + for i in xrange(len(regs)): + c = ExprOp('+', esp, ExprInt(uint32(-(s/8)*(i+1)))) + e.append(ExprAff(ExprMem(c, s), regs[i])) + e.append(ExprAff(esp, c)) + return e + +def popad(): + e = [] + s = 32 + if not s in [16,32]: + raise 'bad size stacker!' + regs = [eax, ecx, edx, ebx, esp, ebp, esi, edi] + regs.reverse() + for i in xrange(len(regs)): + if regs[i] == esp: + continue + c = ExprOp('+', esp, ExprInt(uint32((s/8)*i))) + e.append(ExprAff(regs[i], ExprMem(c, s))) + + c = ExprOp('+', esp, ExprInt(uint32((s/8)*(i+1)))) + e.append(ExprAff(esp, c)) + + return e + + +def call(a, b): + e= [] + c = ExprOp('+', esp, ExprInt(uint32(-4))) + e.append(ExprAff(esp, c)) + e.append(ExprAff(ExprMem(c), a)) + e.append(ExprAff(eip, b)) + return e + +def ret(a = ExprInt(uint32(0))): + e = [] + e.append(ExprAff(esp, ExprOp('+', esp, ExprOp('+', ExprInt(uint32(4)), a)))) + e.append(ExprAff(eip, ExprMem(esp))) + + + return e + +def leave(): + e = [] + e.append(ExprAff(ebp, ExprMem(ebp))) + e.append(ExprAff(esp, ExprOp('+', ExprInt(uint32(4)), ebp))) + return e + +def enter(a,b): + #XXX 32 bit... + e = [] + e.append(ExprAff(ExprMem(esp), ebp)) + e.append(ExprAff(ebp, ExprOp("-", esp, ExprInt(uint32(4))))) + e.append(ExprAff(esp, ExprOp('-', esp, + ExprOp("+", a, ExprInt(uint32(4))) + ) + ) + ) + return e + +def jmp(a): + e= [] + e.append(ExprAff(eip, a)) + return e + +def jz(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', zf, ExprInt(uint32(1))), b, a))) + return e + +def jnz(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', zf, ExprInt(uint32(0))), b, a))) + return e + +def jp(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', pf, ExprInt(uint32(1))), b, a))) + return e + +def jnp(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', pf, ExprInt(uint32(0))), b, a))) + return e + +def ja(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('&', ExprOp('==', cf, ExprInt(uint32(0))), ExprOp('==', zf, ExprInt(uint32(0)))), b, a))) + return e + +def jae(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', cf, ExprInt(uint32(0))), b, a))) + return e + +def jb(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', cf, ExprInt(uint32(1))), b, a))) + return e + +def jbe(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('|', ExprOp('==', cf, ExprInt(uint32(1))), ExprOp('==', zf, ExprInt(uint32(1)))), b, a))) + return e + +def jge(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', nf, of), b, a))) + return e + +def jg(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('&', ExprOp('==', zf, ExprInt(uint32(0))), ExprOp('==', nf, of)), b, a))) + return e + +def jl(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', ExprOp('==', nf, of), ExprInt(uint32(0))), b, a))) + return e + +def jle(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('|', zf, ExprOp('==', ExprOp('==', nf, of), ExprInt(uint32(0)))), b, a))) + return e + +def js(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', nf, ExprInt(uint32(1))), b, a))) + return e + +def jns(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', nf, ExprInt(uint32(0))), b, a))) + return e + +def jo(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(of, b, a))) + return e + +def jno(a, b): + e= [] + e.append(ExprAff(eip, ExprCond(ExprOp('==', of, ExprInt(uint32(0))), b, a))) + return e + + +def loop(a, b): + e= [] + c = ExprOp('-', ecx, ExprInt(uint32(1))) + e.append(ExprAff(ecx, c)) + e.append(ExprAff(eip, ExprCond(ExprOp('==', ExprInt(uint32(0)), ExprOp('==', c, ExprInt(uint32(0)))), b, a))) + return e + +def loopne(a, b): + e= [] + c = ExprOp('-', ecx, ExprInt(uint32(1))) + e.append(ExprAff(ecx, c)) + cond = ExprOp('&', + ExprOp('==', ExprInt(uint32(0)), ExprOp('==', c, ExprInt(uint32(0)))), + ExprOp('==', zf, ExprInt(uint32(0))), + ) + e.append(ExprAff(eip, ExprCond(cond, b, a))) + return e + +#XXX size to do; eflag +def div(a): + e= [] + + s = a.get_size() + if s == 8: + s1,s2 = r_ah, r_al + elif s == 16: + s1,s2 = ExprSlice(edx, 0, 16), ExprSlice(eax, 0, 16) + elif s == 32: + s1,s2 = edx, eax + else: + raise ValueError('div arg not impl', a) + + c_d = ExprOp('div%d'%s, s1, s2, a) + c_r = ExprOp('rem%d'%s, s1, s2, a) + + #if 8 bit div, only ax is affected + if s == 8: + e.append(ExprAff(eax[0:16], ExprCompose([ExprSliceTo(c_d, 0, 8), ExprSliceTo(c_r, 8, 16)]))) + else: + e.append(ExprAff(s1, c_r)) + e.append(ExprAff(s2, c_d)) + return e + +#XXX size to do; eflag +def idiv(a): + e= [] + + s = a.get_size() + + if s == 8: + s1,s2 = r_ah, r_al + elif s == 16: + s1,s2 = r_dx, r_ax + elif s == 32: + s1,s2 = edx, eax + else: + raise ValueError('div arg not impl', a) + + + c_d = ExprOp('idiv%d'%s, s1, s2, a) + c_r = ExprOp('irem%d'%s, s1, s2, a) + + e.append(ExprAff(s1, c_r)) + e.append(ExprAff(s2, c_d)) + return e + +#XXX size to do; eflag +def mul(a): + e= [] + if a.get_size() == 32: + c_hi = ExprOp('umul32_hi', eax, a) + c_lo = ExprOp('umul32_lo', eax, a) + e.append(ExprAff(edx, c_hi)) + e.append(ExprAff(eax, c_lo)) + + e.append(ExprAff(of, ExprCond(ExprOp("==", c_hi, ExprInt(uint32(0))), + ExprInt(uint32(0)), + ExprInt(uint32(1))))) + e.append(ExprAff(cf, ExprCond(ExprOp("==", c_hi, ExprInt(uint32(0))), + ExprInt(uint32(0)), + ExprInt(uint32(1))))) + + + + elif a.get_size() == 16: + c_hi = ExprOp('umul16_hi', r_ax, a) + c_lo = ExprOp('umul16_lo', r_ax, a) + e.append(ExprAff(r_dx, c_hi)) + e.append(ExprAff(r_ax, c_lo)) + + e.append(ExprAff(of, ExprCond(ExprOp("==", c_hi, ExprInt(uint32(0))), + ExprInt(uint32(0)), + ExprInt(uint32(1))))) + e.append(ExprAff(cf, ExprCond(ExprOp("==", c_hi, ExprInt(uint32(0))), + ExprInt(uint32(0)), + ExprInt(uint32(1))))) + + elif a.get_size() == 8: + c = ExprOp('umul08', eax, a) + e.append(ExprAff(eax[:16], c)) + e.append(ExprAff(of, ExprCond(ExprOp("==", eax[8:16], ExprInt(uint32(0))), + ExprInt(uint32(0)), + ExprInt(uint32(1))))) + e.append(ExprAff(cf, ExprCond(ExprOp("==", eax[8:16], ExprInt(uint32(0))), + ExprInt(uint32(0)), + ExprInt(uint32(1))))) + + + + + return e + +#XXX size to do; eflag +def imul(a, b = None, c = None): + e= [] + if b == None: + if a.get_size() == 32: + c_hi = ExprOp('imul32_hi', eax, a) + c_lo = ExprOp('imul32_lo', eax, a) + e.append(ExprAff(edx, c_hi)) + e.append(ExprAff(eax, c_lo)) + elif a.get_size() == 16: + c_hi = ExprOp('imul16_hi', r_ax, a) + c_lo = ExprOp('imul16_lo', r_ax, a) + e.append(ExprAff(r_dx, c_hi)) + e.append(ExprAff(r_ax, c_lo)) + elif a.get_size() == 8: + c = ExprOp('imul08', eax, a) + e.append(ExprAff(eax[:16], c)) + + else: + if c == None: + c = b + b = a + c = ExprOp('*', b, c) + e.append(ExprAff(a, c)) + return e + + +#XXX 16 bit bug +def cdq(): + e = [] + e.append(ExprAff(edx, + ExprCond(ExprOp('==', ExprOp('&', eax, ExprInt(uint32(0x80000000))), ExprInt(uint32(0))), + ExprInt(uint32(0x0)), + ExprInt(uint32(0xffffffff))) + ) + ) + return e + +def stosb(): + e = [] + e.append(ExprAff(ExprMem(edi, 8), eax[0:8])) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(1))), ExprOp('+', edi, ExprInt(uint32(1)))))) + return e + +def stosw(): + e = [] + e.append(ExprAff(ExprMem(edi, 16), eax[0:16])) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(2))), ExprOp('+', edi, ExprInt(uint32(2)))))) + return e + +def stosd(): + e = [] + e.append(ExprAff(ExprMem(edi), eax)) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(4))), ExprOp('+', edi, ExprInt(uint32(4)))))) + return e + +def lodsb(): + e = [] + e.append(ExprAff(eax[0:8], ExprMem(esi, 8))) + e.append(ExprAff(esi, ExprCond(df, ExprOp('-', esi, ExprInt(uint32(1))), ExprOp('+', esi, ExprInt(uint32(1)))))) + return e + +def lodsw(): + e = [] + e.append(ExprAff(eax[0:16], ExprMem(esi, 16))) + e.append(ExprAff(esi, ExprCond(df, ExprOp('-', esi, ExprInt(uint32(2))), ExprOp('+', esi, ExprInt(uint32(2)))))) + return e + +def lodsd(): + e = [] + e.append(ExprAff(eax, ExprMem(esi))) + e.append(ExprAff(esi, ExprCond(df, ExprOp('-', esi, ExprInt(uint32(4))), ExprOp('+', esi, ExprInt(uint32(4)))))) + return e + +def movsb(): + e = [] + e.append(ExprAff(ExprMem(edi, 8), ExprMem(esi, 8))) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(1))), ExprOp('+', edi, ExprInt(uint32(1)))))) + e.append(ExprAff(esi, ExprCond(df, ExprOp('-', esi, ExprInt(uint32(1))), ExprOp('+', esi, ExprInt(uint32(1)))))) + return e + +def movsw(): + e = [] + e.append(ExprAff(ExprMem(edi, 16), ExprMem(esi, 16))) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(2))), ExprOp('+', edi, ExprInt(uint32(2)))))) + e.append(ExprAff(esi, ExprCond(df, ExprOp('-', esi, ExprInt(uint32(2))), ExprOp('+', esi, ExprInt(uint32(2)))))) + return e + +def movsd(): + e = [] + e.append(ExprAff(ExprMem(edi), ExprMem(esi))) + e.append(ExprAff(edi, ExprCond(df, ExprOp('-', edi, ExprInt(uint32(4))), ExprOp('+', edi, ExprInt(uint32(4)))))) + e.append(ExprAff(esi, ExprCond(df, ExprOp('-', esi, ExprInt(uint32(4))), ExprOp('+', esi, ExprInt(uint32(4)))))) + return e + + +def float_pop(avoid_flt = None): + e= [] + if avoid_flt != float_st0: + e.append(ExprAff(float_st0, float_st1)) + if avoid_flt != float_st1: + e.append(ExprAff(float_st1, float_st2)) + if avoid_flt != float_st2: + e.append(ExprAff(float_st2, float_st3)) + if avoid_flt != float_st3: + e.append(ExprAff(float_st3, float_st4)) + if avoid_flt != float_st4: + e.append(ExprAff(float_st4, float_st5)) + if avoid_flt != float_st5: + e.append(ExprAff(float_st5, float_st6)) + if avoid_flt != float_st6: + e.append(ExprAff(float_st6, float_st7)) + if avoid_flt != float_st7: + e.append(ExprAff(float_st7, ExprInt(uint32(0)))) + e.append(ExprAff(float_stack_ptr, ExprOp('-', float_stack_ptr, ExprInt(uint32(1))))) + return e + +# XXX TODO +def fcom(a): + e = [] + if isinstance(a, ExprMem): + src = ExprOp('mem_%.2d_to_double'%a.get_size(), a) + else: + src = a + + e.append(ExprAff(float_c0, ExprOp('fcom_c0', float_st0, src))) + e.append(ExprAff(float_c1, ExprOp('fcom_c1', float_st0, src))) + e.append(ExprAff(float_c2, ExprOp('fcom_c2', float_st0, src))) + e.append(ExprAff(float_c3, ExprOp('fcom_c3', float_st0, src))) + return e + +def ficom(a): + return [] + +def fcomp(a): + e= fcom(a) + e+=float_pop() + return e + +def fld(a): + e= [] + e.append(ExprAff(float_st7, float_st6)) + e.append(ExprAff(float_st6, float_st5)) + e.append(ExprAff(float_st5, float_st4)) + e.append(ExprAff(float_st4, float_st3)) + e.append(ExprAff(float_st3, float_st2)) + e.append(ExprAff(float_st2, float_st1)) + e.append(ExprAff(float_st1, float_st0)) + e.append(ExprAff(float_st0, a)) + e.append(ExprAff(float_stack_ptr, ExprOp('+', float_stack_ptr, ExprInt(uint32(1))))) + return e + +def fst(a): + e = [] + if isinstance(a, ExprMem): + src = ExprOp('double_to_mem_%2d'%a.get_size(), float_st0) + else: + src = float_st0 + + + e.append(ExprAff(a, src)) + return e + +def fstp(a): + e = fst(a) + e+=float_pop(a) + return e + +def fist(a): + e = [] + e.append(ExprAff(a, ExprOp('double_to_int_32', float_st0))) + return e + +def fistp(a): + e = fist(a) + e+=float_pop(a) + return e + +def fild(a): + + #XXXXX + src = ExprOp('int_%.2d_to_double'%a.get_size(), a) + return fld(src) + +def fldz(): + #XXX + return fld(ExprOp('int_32_to_double', ExprInt(uint32(0)))) + +def fadd(a): + e = [] + if isinstance(a, ExprMem): + src = ExprOp('mem_%.2d_to_double'%a.get_size(), a) + else: + src = a + e.append(ExprAff(float_st0, ExprOp('fadd', float_st0, src))) + return e + +def fnstsw(): + dst = eax + return [ExprAff(dst, ExprCompose([ExprSliceTo(ExprInt(uint32(0)), 0, 8), + ExprSliceTo(float_c0, 8, 9), + ExprSliceTo(float_c1, 9, 10), + ExprSliceTo(float_c2, 10, 11), + ExprSliceTo(float_stack_ptr, 11, 14), + ExprSliceTo(float_c3, 14, 15), + ExprSliceTo(ExprInt(uint32(0)), 15, 16), + ExprSliceTo(ExprSlice(dst, 16, dst.get_size()), 16, dst.get_size()) + ]))] + +def fnstcw(a): + e = [] + e.append(ExprAff(a, float_control)) + return e + +def fldcw(a): + e = [] + e.append(ExprAff(float_control, a)) + return e + +def fwait(): + return [] + +def nop(): + return [] + +def hlt(): + return [] + +def rdtsc(): + e = [] + e.append(ExprAff(eax, tsc1)) + e.append(ExprAff(edx, tsc2)) + return e + +def cbw(a): + e = [] + cast_int = tab_uintsize[a.get_size()] + b = ExprOp('<<', ExprInt(cast_int(-1)), + ExprInt(cast_int(a.get_size()/2))) + + e.append(ExprAff(a, ExprCond( + ExprOp('==', ExprInt(cast_int(0)), + ExprOp('&', a, ExprOp('<<',ExprInt(cast_int(1)), + ExprOp('-', ExprInt(cast_int(a.get_size()/2)), + ExprInt(cast_int(1)) + ) + ) + ) + ), + a, + ExprOp('|', a, b), + ) + )) + + return e + +# XXX TODO +def daa(): + return [] + +def aam(a): + return [] + +def aad(a): + return [] + +def aaa(): + return [] + +def bsf(a, b): + e = [] + cast_int = tab_uintsize[b.get_size()] + e.append(ExprAff(a, ExprOp('bsf', a, b))) + e.append(ExprAff(zf, ExprOp('==', ExprInt(cast_int(0)), b))) + return e + +def bsr(a, b): + e = [] + cast_int = tab_uintsize[b.get_size()] + e.append(ExprAff(a, ExprOp('bsr', a, b))) + e.append(ExprAff(zf, ExprOp('==', ExprInt(cast_int(0)), b))) + return e + +def arpl(a, b): + e= [] + e.append(ExprAff(ExprId('vmcpu.vm_exception_flags'), ExprInt(uint32(1<<7)))) + return e + +def ins(): + e= [] + e.append(ExprAff(ExprId('vmcpu.vm_exception_flags'), ExprInt(uint32(1<<7)))) + return e + +def sidt(a): + e = [] + if not isinstance(a, ExprMem) or a.size!=32: + raise 'not exprmem 32bit instance!!' + b = a.arg + cast_int = tab_uintsize[a.get_size()] + print "DEFAULT SIDT ADDRESS %s!!"%str(a) + e.append(ExprAff(ExprMem(b, 32), ExprInt(uint32(0xe40007ff)))) + e.append(ExprAff(ExprMem(ExprOp("+", b, ExprInt(uint32(4))), 32), ExprInt(uint32(0x8245)))) + return e + + +def cmovz(a, b): + e= [] + e.append(ExprAff(a, ExprCond(ExprOp('==', zf, ExprInt(uint32(1))), b, a))) + return e +def cmovnz(a, b): + e= [] + e.append(ExprAff(a, ExprCond(ExprOp('==', zf, ExprInt(uint32(0))), b, a))) + return e + +#XXX +def l_int(a): + e= [] + e.append(ExprAff(ExprId('vmcpu.vm_exception_flags'), ExprInt(uint32(1<<1)))) #SOFT BP + return e + +def l_sysenter(): + e= [] + e.append(ExprAff(ExprId('vmcpu.vm_exception_flags'), ExprInt(uint32(EXCEPT_PRIV_INSN)))) + return e + +#XXX +def l_outs(): + e= [] + e.append(ExprAff(ExprId('vmcpu.vm_exception_flags'), ExprInt(uint32(EXCEPT_PRIV_INSN)))) #SOFT BP + return e + +# XXX actually, xlat performs al = (ds:[e]bx + ZeroExtend(al)) +def xlat(): + e= [] + a = ExprCompose([ExprSliceTo(ExprInt(uint32(0)), 8, 32), ExprSliceTo(eax[0:8], 0, 8)]) + b = ExprMem(ExprOp('+', ebx, a), 8) + e.append(ExprAff(eax[0:8], b)) + return e + +def cpuid(): + e = [] + e.append(ExprAff(eax, ExprOp('cpuid', eax, ExprInt(uint32(0))))) + e.append(ExprAff(ebx, ExprOp('cpuid', eax, ExprInt(uint32(1))))) + e.append(ExprAff(ecx, ExprOp('cpuid', eax, ExprInt(uint32(2))))) + e.append(ExprAff(edx, ExprOp('cpuid', eax, ExprInt(uint32(3))))) + return e + +def bt(a, b): + cast_int = tab_uintsize[a.get_size()] + e= [] + c= ExprOp('&', b, ExprInt(cast_int(b.get_size() - 1))) + d= ExprOp('>>', a, c) + e.append(ExprAff(cf, ExprOp('&', d, ExprInt(cast_int(1))))) + return e + +def btc(a, b): + cast_int = tab_uintsize[a.get_size()] + e= [] + c= ExprOp('&', b, ExprInt(cast_int(b.get_size() - 1))) + d= ExprOp('>>', a, c) + m= ExprOp('<<', ExprInt(cast_int(1)), b) + e.append(ExprAff(cf, ExprOp('&', d, ExprInt(cast_int(1))))) + e.append(ExprAff(a, ExprOp('^', a, m))) + return e + +def bts(a, b): + cast_int = tab_uintsize[a.get_size()] + e= [] + c= ExprOp('&', b, ExprInt(cast_int(b.get_size() - 1))) + d= ExprOp('>>', a, c) + m= ExprOp('<<', ExprInt(cast_int(1)), b) + e.append(ExprAff(cf, ExprOp('&', d, ExprInt(cast_int(1))))) + e.append(ExprAff(a, ExprOp('|', a, m))) + return e + +def btr(a, b): + cast_int = tab_uintsize[a.get_size()] + e= [] + c= ExprOp('&', b, ExprInt(cast_int(b.get_size() - 1))) + d= ExprOp('>>', a, c) + m= ExprOp('!', ExprOp('<<', ExprInt(cast_int(1)), b)) + e.append(ExprAff(cf, ExprOp('&', d, ExprInt(cast_int(1))))) + e.append(ExprAff(a, ExprOp('&', a, m))) + return e + + +def into(): + return [] + +def l_in(a, b): + return [] + +def cmpxchg(a, b, c): + e = [] + cast_int = tab_uintsize[a.get_size()] + + cond = ExprOp('==', a, c ) + e.append(ExprAff(zf, cond)) + e.append(ExprAff(c, ExprCond(cond, + b, + c) + )) + e.append(ExprAff(a, ExprCond(cond, + a, + c) + )) + return e + + + +mnemo_func = {'mov': mov, + 'xchg': xchg, + 'movzx': movzx, + 'movsx': movsx, + 'lea': lea, + 'add':add, + 'xadd':xadd, + 'adc':adc, + 'sub':sub, + 'sbb':sbb, + 'neg':neg, + 'not':l_not, + 'cmp':l_cmp, + 'xor':xor, + 'or':l_or, + 'and':l_and, + 'test':l_test, + 'rol':l_rol, + 'ror':l_ror, + 'rcl':rcl, + 'rcr':rcr, + 'sar':sar, + 'shr':shr, + 'shrd_cl':shrd_cl, + 'sal':sal, + 'shl':shl, + 'shld_cl':shld_cl, + 'cmc':cmc, + 'clc':clc, + 'stc':stc, + 'cld':cld, + 'std':std, + 'cli':cli, + 'sti':sti, + 'bsf':bsf, + 'bsr':bsr, + 'inc':inc, + 'dec':dec, + 'push':push, + 'pop':pop, + 'sete':sete, + 'setnz':setnz, + 'setl':setl, + 'setg':setg, + 'setge':setge, + 'seta':seta, + 'setb':setb, + 'setns':setns, + 'sets':sets, + 'seto':seto, + 'bswap':bswap, + 'cmpsb':cmpsb, + 'cmpsw':cmpsw, + 'cmpsd':cmpsd, + 'scasb':scasb, + 'scasw':scasw, + 'scasd':scasd, + 'pushfd':pushfd, + 'pushfw':pushfw, + 'popfd':popfd, + 'pushad':pushad, + 'popad':popad, + 'call':call, + 'ret':ret, + 'leave':leave, + 'enter':enter, + 'jmp':jmp, + 'jz':jz, + 'je':jz, + 'jnz':jnz, + 'jp':jp, + 'jnp':jnp, + 'ja':ja, + 'jae':jae, + 'jb':jb, + 'jbe':jbe, + 'jg':jg, + 'jge':jge, + 'jl':jl, + 'jle':jle, + 'js':js, + 'jns':jns, + 'jo':jo, + 'jno':jno, + 'loop':loop, + 'loopne':loopne, + 'div':div, + 'mul':mul, + 'imul':imul, + 'idiv':idiv, + 'cdq':cdq, + 'cbw':cbw, + 'daa':daa, + 'aam':aam, + 'aad':aad, + 'aaa':aaa, + 'shrd':shrd, + 'stosb':stosb, + 'stosw':stosw, + 'stosd':stosd, + 'lodsb':lodsb, + 'lodsw':lodsw, + 'lodsd':lodsd, + 'movsb':movsb, + 'movsw':movsw, + 'movsd':movsd, + 'fcomp':fcomp, + 'nop':nop, + 'fnop':nop, #XXX + 'hlt':hlt, + 'rdtsc':rdtsc, + 'fst':fst, + 'fstp':fstp, + 'fist':fist, + 'fistp':fistp, + 'fld':fld, + 'fldz':fldz, + 'fild':fild, + 'fadd':fadd, + 'fnstsw':fnstsw, + 'fnstcw':fnstcw, + 'fldcw':fldcw, + 'fwait':fwait, + 'sidt':sidt, + 'arpl':arpl, + 'cmovz':cmovz, + 'cmove':cmovz, + 'cmovnz':cmovnz, + 'int':l_int, + 'xlat': xlat, + 'bt':bt, + 'cpuid':cpuid, + 'jo': jo, + 'fcom':fcom, + 'ficom':ficom, + 'ins':ins, + 'btc':btc, + 'bts':bts, + 'btr':btr, + 'into':into, + 'in':l_in, + 'outs':l_outs, + "sysenter":l_sysenter, + "cmpxchg":cmpxchg, + } + + + +class ia32_rexpr: + + noad = "no_ad" + ad = "ad" + + ad8 = "ad8" + ad16 = "ad16" + ad32 = "ad32" + segm = "segm" + + size = "size" + + symb = "symb__intern__" + + imm = "imm" + s08 = "s08" + u08 = "u08" + u16 = "u16" + s16 = "s16" + u32 = "u32" + s32 = "s32" + + f32 = "f32" + f64 = "f64" + + im1 = "im1" + im3 = "im3" + ims = "ims" + mim = "mim" + + + dict_size = {imm:'imm', + s08:'b', + u08:'B', + s16:'h', + u16:'H', + s32:'i', + u32:'I', + } + + + + r_eax = eax + r_ecx = ecx + r_edx = edx + r_ebx = ebx + r_esp = esp + r_ebp = ebp + r_esi = esi + r_edi = edi + + r_dr0 = dr0 + r_dr1 = dr1 + r_dr2 = dr2 + r_dr3 = dr3 + r_dr4 = dr4 + r_dr5 = dr5 + r_dr6 = dr6 + r_dr7 = dr7 + + r_cr0 = cr0 + r_cr1 = cr1 + r_cr2 = cr2 + r_cr3 = cr3 + r_cr4 = cr4 + r_cr5 = cr5 + r_cr6 = cr6 + r_cr7 = cr7 + + r_ax = r_eax[:16] + r_cx = r_ecx[:16] + r_dx = r_edx[:16] + r_bx = r_ebx[:16] + r_sp = r_esp[:16] + r_bp = r_ebp[:16] + r_si = r_esi[:16] + r_di = r_edi[:16] + + r_al = r_eax[:8] + r_cl = r_ecx[:8] + r_dl = r_edx[:8] + r_bl = r_ebx[:8] + r_ah = r_eax[8:16] + r_ch = r_ecx[8:16] + r_dh = r_edx[8:16] + r_bh = r_ebx[8:16] + + + r_es = es + r_cs = cs + r_ss = ss + r_ds = ds + r_fs = fs + r_gs = gs + + reg_list8 =[r_al, r_cl, r_dl, r_bl, + r_ah, r_ch, r_dh, r_bh] + reg_list16=[r_ax, r_cx, r_dx, r_bx, + r_sp, r_bp, r_si, r_di] + reg_list32=[r_eax, r_ecx, r_edx, r_ebx, + r_esp, r_ebp, r_esi, r_edi] + + reg_listsg=[r_es, r_cs, r_ss, r_ds, + r_fs, r_gs] + reg_listdr=[r_dr0, r_dr1, r_dr2, r_dr3, r_dr4, r_dr5, r_dr6, r_dr7] + reg_listcr=[r_cr0, r_cr1, r_cr2, r_cr3, r_cr4, r_cr5, r_cr6, r_cr7] + + reg_flt = [float_st0, float_st1, float_st2, float_st3, float_st4, float_st5, float_st6, float_st7] + + reg_dict = {} + for i in range(8): + reg_dict[reg_list8[i]] = i + for i in range(8): + reg_dict[reg_list16[i]] = i + for i in range(8): + reg_dict[reg_list32[i]] = i + for i in range(8): + reg_dict[reg_flt[i]] = i + + + +def dict_to_Expr(d, modifs = {}, mnemo_mode = x86_afs.u32): + size = [x86_afs.u32, x86_afs.u08][modifs[w8]==True] + #overwrite w8 + if modifs[sd]!=None: + size = [x86_afs.f32, x86_afs.f64][modifs[sd]==True] + if modifs[wd]: + size = x86_afs.u16 + + + tab32 = {ia32_rexpr.u08:ia32_rexpr.reg_list8, ia32_rexpr.u16:ia32_rexpr.reg_list16, ia32_rexpr.u32:ia32_rexpr.reg_list32,ia32_rexpr.f32:ia32_rexpr.reg_flt} + tab16 = {ia32_rexpr.u08:ia32_rexpr.reg_list8, ia32_rexpr.u16:ia32_rexpr.reg_list32, ia32_rexpr.u32:ia32_rexpr.reg_list16} + ad_size = {ia32_rexpr.u08:ia32_rexpr.u08, ia32_rexpr.u16:ia32_rexpr.u16, ia32_rexpr.u32:ia32_rexpr.u32, ia32_rexpr.f32:ia32_rexpr.u32, ia32_rexpr.f64:ia32_rexpr.u32} + + if is_reg(d): + n = [x for x in d if type(x) in [int, long]] + if len(n)!=1: + raise "bad reg! %s"%str(d) + n = n[0] + if x86_afs.size in d and d[x86_afs.size] == x86_afs.size_seg : + t = ia32_rexpr.reg_listsg + elif ia32_rexpr.size in d: + my_s = d[x86_afs.size] + if my_s == x86_afs.f64: + my_s = x86_afs.u32 + t = tab32[my_s] + else: + if mnemo_mode == u32: + t = tab32[size] + else: + t = tab16[size] + if modifs[dr] and n>0x7: + t = ia32_rexpr.reg_listdr + n&=7 + if modifs[cr] and n>0x7: + t = ia32_rexpr.reg_listcr + n&=7 + if modifs[sg] and n>0x7: + t = ia32_rexpr.reg_listsg + n&=7 + if modifs[sd] is not None: + t = tab32[size] + n&=7 + + out = t[n] + elif is_imm(d): + if ia32_rexpr.imm in d: + #test bug imm 16b + if mnemo_mode == x86_afs.u16: + if size == x86_afs.u16: + size = x86_afs.u32 + else: + size = x86_afs.u16 + + + #print d + out = ExprInt(tab_afs_int[size](d[ia32_rexpr.imm])) + if ia32_rexpr.symb in d: + if len(d[ia32_rexpr.symb])!=1: + raise "not impl symb diff 1:x",str(d[ia32_rexpr.symb]) + myname = d[ia32_rexpr.symb].keys()[0] + myval = myname.offset + if myname.offset == None: + return ExprId(myname.name) + + + #XXX todo hack gen C + return ExprInt(uint32(myval)) + if type(myname)!=str: + return ExprId(myname.name) + return ExprInt(uint32(myval)) + elif is_address(d): + + size = {ia32_rexpr.u08:8, ia32_rexpr.u16:16, ia32_rexpr.u32:32, ia32_rexpr.f32:32, ia32_rexpr.f64:64}[size] + + if ia32_rexpr.size in d: + size = d[ia32_rexpr.size] + msize = {ia32_rexpr.u08:8, ia32_rexpr.u16:16, ia32_rexpr.u32:32, ia32_rexpr.f32:32, ia32_rexpr.f64:64} + if size in msize: + size = msize[size] + if ia32_rexpr.segm in d: + pass + out = [] + for k in d: + if k in [ia32_rexpr.ad, ia32_rexpr.size]: + continue + elif k in [ia32_rexpr.segm]: + if d[k] == 4: + out.append(ExprInt(uint32(0x7FF70000))) + elif k == ia32_rexpr.imm: + out.append(ExprInt(d[k])) + elif type(k) in [int, long]: + if d[k] ==1: + out.append(ia32_rexpr.reg_list32[k]) + else: + out.append(ExprOp('*', ExprInt(uint32(d[k])), ia32_rexpr.reg_list32[k])) + elif k == ia32_rexpr.symb: + print 'warning: symbol.. in mem look', d[k] + out.append(ExprId(str(d[k].items()[0][0].name))) + else: + raise 'strange ad componoant: %s'%str(d) + if not out: + raise 'arg zarb expr %s'%str(d) + e = out[0] + for o in out[1:]: + e = ExprOp('+', e, o) + out = ExprMem(e, size) + + else: + raise 'unknown arg %s'%str(d) + return out + + + diff --git a/miasm/arch/ppc_arch.py b/miasm/arch/ppc_arch.py new file mode 100644 index 00000000..8cb66b2d --- /dev/null +++ b/miasm/arch/ppc_arch.py @@ -0,0 +1,2294 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +import shlex +import struct + +from miasm.core.bin_stream import bin_stream + + +def hex2bin(op): + out = [] + for i in xrange(31, -1, -1): + out.append(str((op>>i)&1)) + for i in xrange(32, -1, -4): + out[i:i] = ' ' + return "".join(out) + +def myrol(v, r): + return ((v&0xFFFFFFFFL)>>r) | ((v << (32-r))&0xFFFFFFFFL) + +def str2imm(i): + if i.startswith('0x') or i.startswith('-0x'): + d =16 + else: + d = 10 + try: + a = int(i, d) + except: + return False + return a + +def imm2str(i): + if type(i) in [int, long]: + if i<0: + return "-0x%x"%-i + else: + return "0x%x"%i + return str(i) + +def is_imm(i): + return type(str2imm(i)) is not bool + +class bm_meta(type): + def __new__(cls, name, bases, odct): + if name is "bm": + return type.__new__(cls, name, bases, odct) + dct = {'fbits':None, 'l':None, "p_property":[], "checkinv" : False} + dct.update(odct) + + pname = None + if name.startswith('bm_'): + pname = name[3:] + dct["p_property"] = [pname]+dct["p_property"] + + b = bases[0] + + dct["check"] = b.check_no + l = dct["l"] + fbits = dct["fbits"] + if fbits: + l = len(fbits) + allbits = list(fbits) + allbits.reverse() + fbits = 0 + fmask = 0 + while allbits: + a = allbits.pop() + if a in '01': + a = int(a) + fbits<<=1 + fmask<<=1 + fbits|=[0, a][type(a) is int] + fmask|=[0, 1][type(a) is int] + dct["l"] = l + dct["fbits"] = fbits + #for bm int + if pname: + dct[pname] = fbits + dct['fmask'] = fmask + if dct['checkinv']: + dct["check"] = b.check_fbits_inv + else: + dct["check"] = b.check_fbits + + p_property = dct["p_property"] + + for p in p_property: + dct["get_"+p] = lambda self, p=p:getattr(self, p) + dct["set_"+p] = lambda self, p=p:setattr(self, p) + return type.__new__(cls, name, bases, dct) + + +class bm(object): + __metaclass__ = bm_meta + def __init__(self, parent, off, set_at = True): + self.parent = parent + self.off = off-self.l + def __repr__(self): + return "<W-"+str(self.__class__)+str(self.off+self.l-1)+" "+str(self.off)+">" + def check_no(self, v): + return True + def check_fbits(self, v): + return (v>>self.off) & self.fmask == self.fbits + def check_fbits_inv(self, v): + return (v>>self.off) & self.fmask != self.fbits + + def get_val(self, v): + return (v>>self.off) & ((1<<self.l)-1) + def set_val(self, v = None): + + if v == None and len(self.p_property) >= 1: + p = self.p_property[0] + v = getattr(self, p) + return (v&((1<<self.l)-1))<<self.off + + def bin(self): + return self.set_val() + + def parse(self, v): + if len(self.p_property) >= 1: + p = self.p_property[0] + val = self.get_val(v) + setattr(self, p, val) + return True + def setprop(self, val = None): + if len(self.p_property) >= 1: + p = self.p_property[0] + if not hasattr(self, p): + setattr(self, p, None) + + +all_bm_int = [] +for i in xrange(0x40): + mask_str = hex2bin(i).replace(' ', '')[26:] + while mask_str: + bstr = "bm_int"+mask_str + globals()[bstr] = bm_meta(bstr,(bm,),{"fbits":mask_str}) + if mask_str[0] !='0': + break + mask_str = mask_str[1:] + + +class bm_set_meta(type): + def __new__(cls, name, bases, odct): + if not 'l' in odct: + odct['l'] = 9 + return type.__new__(cls, name, bases, odct) + + +class bm_set(object): + __metaclass__ = bm_set_meta + def __init__(self, parent, off): + self.parent = parent + self.off = 32-off-self.l + self.fmask = (1<<self.l)-1 + def check(self, v): + return (v>>self.off) & self.fmask in self.fbits + + +COND_EQ = 0 +COND_NE = 1 +COND_CS = 2 +COND_CC = 3 +COND_MI = 4 +COND_PL = 5 +COND_VS = 6 +COND_VC = 7 +COND_HI = 8 +COND_LS = 9 +COND_GE = 10 +COND_LT = 11 +COND_GT = 12 +COND_LE = 13 +COND_AL = 14 +COND_NV = 15 + +class bm_cond(bm): + l = 4 + p_property = ["cond2str", 'str2cond'] + n = ['EQ', 'NE', 'CS', 'CC', 'MI', 'PL', 'VS', 'VC', 'HI', 'LS', 'GE', 'LT', 'GT', 'LE', 'AL', 'NV'] + + def cond2str(self): + return self.n[self.cond] + + def str2cond(self, cond): + if not cond in self.n: + raise ValueError('unknown cond') + self.cond = self.n.index(cond) + +class bm_int000000000(bm): + fbits = '000000000' + +class bm_accum(bm): + l = 1 + n = ['MUL', 'MLA'] + def name2str(self): + return self.n[self.accum] + + def str2name(self, name): + if not name in self.n: + raise ValueError('unknown name') + self.accum = self.n.index(name) + +class bm_immop(bm): + l = 1 + +class bm_opsz(bm): + l = 1 + +class bm_szext(bm): + l = 2 + +class bm_rot(bm): + l = 2 + +class bm_scc(bm): + l = 1 + p_property = ["scc2str"] + def scc2str(self): + return ['', 'S'][self.scc==1] + +class bm_lnk(bm): + l = 1 + p_property = ["lnk2str"] + def lnk2str(self): + return ['', 'L'][self.lnk==1] + +class bm_offs(bm): + l = 24 + + def parse(self, v): + val = self.get_val(v) + val<<=2 + if val & (1<<25): + val |=0xFC000000 + self.offs = val + return True + def bin(self): + v = (self.offs>>2)&0xffffff + return self.set_val(v) + +class bm_cooff(bm): + l = 8 + + def parse(self, v): + val = self.get_val(v) + val<<=2 + self.cooff = val + return True + def bin(self): + v = (self.cooff>>2)&0xff + return self.set_val(v) + +class bm_size(bm): + l = 1 + p_property = ["size2str"] + def size2str(self): + return ['', 'B'][self.size==1] + +class bm_tlen(bm): + l = 1 + +class bm_ppndx(bm): + l = 1 + +class bm_updown(bm): + l = 1 + +class bm_psr(bm): + l = 1 + +class bm_wback(bm): + l = 1 + +class bm_ldst(bm): + l = 1 + +class bm_reglist(bm): + l = 16 + + def parse(self, v): + val = self.get_val(v) + self.reglist = [] + for i in xrange(0x10): + if val & (1<<i): + self.reglist.append(i) + return True + def bin(self): + v = 0 + for r in self.reglist: + v|=(1<<r) + return self.set_val(v) + + +class bm_rt(bm): + l = 5 + +class bm_rs(bm): + l = 5 + +class bm_ra(bm): + l = 5 + +class bm_bo(bm): + l = 5 + +class bm_bi(bm): + l = 5 + +class bm_bd(bm): + l = 14 + +class bm_rb(bm): + l = 5 + +class bm_oe(bm): + l = 1 + +class bm_rc(bm): + l = 1 + +class bm_opc5(bm): + l = 5 + +class bm_opc9(bm): + l = 9 + +class bm_opc10(bm): + l = 10 + +class bm_nb(bm): + l = 5 + +class bm_spr(bm): + l = 10 + +class bm_sr(bm): + l = 4 + +class bm_mb(bm): + l = 5 + +class bm_me(bm): + l = 5 + +class bm_sh(bm): + l = 5 + +class bm_to(bm): + l = 5 + +class bm_fra(bm): + l = 5 + +class bm_frb(bm): + l = 5 + +class bm_frc(bm): + l = 5 + +class bm_frt(bm): + l = 5 + + + + + + +class bm_simm(bm): + l = 16 + +class bm_uimm(bm): + l = 16 + +class bm_li(bm): + l = 24 + +class bm_aa(bm): + l = 1 + +class bm_lk(bm): + l = 1 + +class bm_bf(bm): + l = 3 + +class bm_bfa(bm): + l = 3 + +class bm_bt(bm): + l = 5 + +class bm_ba(bm): + l = 5 + +class bm_bb(bm): + l = 5 + +class bm_rn(bm): + l = 4 + + +class bm_rdh(bm): + l = 4 + +class bm_rdl(bm): + l = 4 + + +class ppc_mnemo_metaclass(type): + global tab_mn + def __call__(cls, op, offset = 0): + if type(op) in [int, long]: + cls = cls.class_from_op(op) + i = cls.__new__(cls) + i.__init__(op, offset) + elif type(op) is str: + cls = cls.asm(op) + i = cls.__new__(cls) + i.__init__(op, 0, False) + else: + raise ValueError('zarb arg') + return i + + def class_from_op(cls, op): + ret = filter(lambda x:x.check(op), tab_mn) + if len(ret)==1: + return ret[0] + raise ValueError('ambiquity %s'%str(ret)) + + + def dis(cls, bin, *kargs): + if type(bin) == str: + bin = bin_stream(bin) + elif not isinstance(bin, bin_stream): + raise ValueError('unknown input') + + op = bin.readbs(4) + op = struct.unpack('>L', op)[0] + return cls(op, bin.offset-4) + + + def asm(cls, txt, symbol_reloc_off = []): + print txt + t = ppc_mn.pre_parse_mnemo(txt) + name = t.pop() + ret = filter(lambda x:x.check_mnemo(name), tab_mn) + if len(ret)!=1: + raise ValueError('parse name err %s'%str(ret)) + cls = ret[0] + i = cls.__new__(cls) + i.__init__(txt, 0, False) + return [struct.pack('>L', i.bin())] + + def __new__(cls, name, bases, dct): + ret_c = type.__new__(cls, name, bases, dct) + if name is "ppc_mn": + return ret_c + + mask = [] + if 'mask' in dct: + for off in dct['mask']: + mc = dct['mask'][off](None, off)#+1) + mask.append(mc) + + mask_orig = dct["mask_list"] + ret_c.mask_orig = mask_orig + off = 32 + for m in mask_orig: + mc = m(None, off) + off-=mc.l + mask.append(mc) + for pname in m.p_property: + pfunc = "get_"+pname + p = property(lambda self=ret_c, pname=pname:getattr(getattr(self, "bm_"+pname), pname), + lambda self=ret_c,val=None,pname=pname:setattr(getattr(self, "bm_"+pname), pname, val)) + + setattr(ret_c, pname, p) + + if off!=0: + raise ValueError('invalid mnemonic %d'%off) + ret_c.mask_chk = mask + + #gen arg parser/generator if present + if 'do_args' in dct: + ret_c.args_list = dct['do_args'] + + args2str_f = None + parse_args_f = None + for tmp_cls in bases: + if 'gen_args2str' in tmp_cls.__dict__: + args2str_f = tmp_cls.__dict__['gen_args2str'] + if 'gen_parse_args' in tmp_cls.__dict__: + parse_args_f = tmp_cls.__dict__['gen_parse_args'] + + ret_c.args2str = args2str_f + ret_c.parse_args = parse_args_f + + return ret_c + + def check(self, op): + for m in self.mask_chk: + if m.fbits==None: + continue + if not m.check(op): + return False + return True + + def check_opts(self, rest): + if rest: + return False + return True + + def check_mnemo(self, mnemo): + found = False + for n in self.namestr: + if mnemo.startswith(n): + found = True + break + if not found: + return False + rest = mnemo[len(n):] + return self.check_opts(rest) + + def pre_parse_mnemo(cls, args): + tmp = args.replace(',', ' ') + t = [] + is_minux = False + for x in shlex.shlex(tmp): + if x == '-': + is_minux = True + continue + if is_minux: + x = '-'+x + is_minux = False + + if x == '.': + t[-1]+=x + else: + t.append(x) + + t.reverse() + return t + + def parse_mnemo(cls, args): + t = cls.pre_parse_mnemo(args) + t.reverse() + return [], t[0], t[1:] + + def parse_address(self, a): + return parse_ad(a) + def prefix2hex(self, p): + return "" + +regs_str = ['R%d'%r for r in xrange(0x20)] +regs_str[1] = 'SP' + +cop_str = ['P%d'%r for r in xrange(0x10)] +copr_str = ['C%d'%r for r in xrange(0x10)] + +crb_str = [] +for i in xrange(0x8): + for x in ['LT', 'GT', 'EQ', 'SO']: + crb_str.append('CR%d_%s'%(i, x)) + +cr_str = ['CR%d'%r for r in xrange(0x8)] +fpr_str = ['FP%d'%r for r in xrange(0x20)] +spr_str = ['SPR%d'%r for r in xrange(0x400)] +spr_str[256] = 'LR' +spr_str[392] = 'BL' +spr_str[424] = 'BU' +spr_str[832] = 'SR0' +spr_str[864] = 'SR1' +spr_str[529] = 'IC_CSR' +spr_str[964] = 'ICTRL' +spr_str[288] = 'CTR' + +sr_str = ['SR%d'%r for r in xrange(0x10)] + +all_regs = regs_str+cop_str+copr_str+cr_str+crb_str+fpr_str+spr_str + +from ia32_reg import x86_afs + + +def is_symbol(a): + if is_imm(a) or a in all_regs: + return False + return True + +def parse_ad(a): + a = a.strip() + if is_symbol(a): + print 'SYMBOL!', a + return {x86_afs.symb:{a:1}} + else: + return {0x1337:1} + + +def reg2str(r): + return regs_str[r] +def str2reg(r): + return regs_str.index(r) + + +def cr2str(r): + return cr_str[r] +def str2cr(r): + return cr_str.index(r) + +def crb2str(r): + return crb_str[r] +def str2crb(r): + return crb_str.index(r) + + +def fpr2str(r): + return fpr_str[r] +def str2fpr(r): + return fpr_str.index(r) + +def spr2str(r): + return spr_str[r] +def str2spr(r): + return spr_str.index(r) + + +def sr2str(r): + return sr_str[r] +def str2sr(r): + return sr_str.index(r) + +class reg: + @classmethod + def str(cls, r): + return reg2str(r) + @classmethod + def cls(cls, r): + return str2reg(r) + +class imm: + @classmethod + def str(cls, r): + return imm2str(r) + @classmethod + def cls(cls, r): + return str2imm(r) + +class crb: + @classmethod + def str(cls, r): + return crb2str(r) + @classmethod + def cls(cls, r): + return str2crb(r) + + +class fpr: + @classmethod + def str(cls, r): + return fpr2str(r) + @classmethod + def cls(cls, r): + return str2fpr(r) + + +class cr: + @classmethod + def str(cls, r): + return cr2str(r) + @classmethod + def cls(cls, r): + return str2cr(r) + +class spr: + @classmethod + def str(cls, r): + return spr2str(r) + @classmethod + def cls(cls, r): + return str2spr(r) + +class sr: + @classmethod + def str(cls, r): + return sr2str(r) + @classmethod + def cls(cls, r): + return str2sr(r) + +def args2reduce(args): + out = [] + for a in args: + if type(a) is list: + out+=args2reduce(a) + else: + out.append(a) + return out + +def arglist2str(args): + out = "" + for a in args: + if a in ['[', ']', 'LSL', 'LSR', 'ASR', 'ROR']: + out+=a+' ' + else: + out+=a + out+=', ' + if out.endswith(', '): + out = out[:-2] + return out + + +def args2str(args): + return arglist2str(args2reduce(args)) + + +class ppc_mn(object): + mask_list = [] + __metaclass__ = ppc_mnemo_metaclass + + + def gen_args2str(self): + args = [] + for r, t in self.args_list: + args.append(t.str(getattr(self, r))) + return args + + def gen_parse_args(self, args): + for r, t in self.args_list: + setattr(self, r, t.cls(args.pop())) + + def __init__(self, op, offset = 0, dis = True): + off=32 + mask = [] + self.offset = offset + self.l = 4 + self.m = None + self.arg = [] + + for m in self.mask_orig: + mc = m(self, off) + off-=mc.l + for pname in m.p_property: + setattr(self, "bm_"+pname, mc) + mask.append(mc) + self.mask = mask + + if dis: + for m in self.mask: + ret = m.parse(op) + if not ret: + raise ValueError('cannot parse %.8X'%op) + else: + for m in self.mask: + ret = m.setprop() + + full_mnemo = ppc_mn.pre_parse_mnemo(op) + mnemo = full_mnemo.pop() + name, rest = self.parse_name_cond(mnemo) + self.name = name + self.parse_opts(rest) + self.str2name(name) + + mnemo_nosymb = [] + for a in full_mnemo: + if not is_symbol(a) or a in bm_cond.n: + mnemo_nosymb.append(a) + continue + print "WARNING asm symb", a + mnemo_nosymb.append("0") + full_mnemo = mnemo_nosymb + + self.parse_args(full_mnemo) + + def parse_opts(self, rest): + if rest: + raise ValueError('should not have rest here ', rest) + pass + def str2name(self, n): + pass + + def getname(self): + name = self.name2str()+self.oe2str()+self.rc2str() + return name + + def bin(self): + v = 0 + for m in self.mask: + if not m.checkinv: + v|=m.bin() + return v + + def args2str(self): + args = ["NO ARGS"] + return args + + def __str__(self): + name = self.getname() + args = self.args2str() + args = args2str(args) + return name+" "+args + + def parse_name_cond(self, mnemo): + name = None + for i, n in enumerate(self.namestr): + if mnemo.startswith(n): + name = n + break + if name == None: + raise ValueError('cannot parse name') + + rest = mnemo[len(n):] + return name, rest + + def oe2str(self): + return "" + def rc2str(self): + return "" + + + def breakflow(self): + return False + def splitflow(self): + return False + def dstflow(self): + return False + + def getnextflow(self): + return self.offset+self.l + + def fix_symbol(self, s): + pass + + +MN_AND = 0 +MN_EOR = 1 +MN_SUB = 2 +MN_RSB = 3 +MN_ADD = 4 +MN_ADC = 5 +MN_SBC = 6 +MN_RSC = 7 +MN_TST = 8 +MN_TEQ = 9 +MN_CMP = 10 +MN_CMN = 11 +MN_ORR = 12 +MN_MOV = 13 +MN_BIC = 14 +MN_MVN = 15 + +class ppc_add(ppc_mn): + mask_list = [bm_int011111, bm_rt, bm_ra, bm_rb, bm_oe, bm_opc9, bm_rc] + namestr = ['ADDE', 'ADDC', 'ADD', 'DIVWU', "DIVW", 'MULLW', 'SUBFC', 'SUBFE', 'SUBF'] + namsdct = {'ADD':266, 'ADDC':10, 'ADDE':138, 'DIVWU':459, 'DIVW':491, 'MULLW':235, 'SUBFC':8, 'SUBF':40, 'SUBFE':136} + mask = {22:bm_set_meta("bm_addopc",(bm_set,),{"fbits":namsdct.values()})} + + strname = dict((x[1], x[0]) for x in namsdct.items()) + + do_args = [('rt',reg), ('ra',reg), ('rb',reg)] + + def name2str(self): + return self.strname[self.opc9] + def str2name(self, n): + self.opc9 = self.namsdct[n] + @classmethod + def check_opts(cls, rest): + if rest in ["", ".", "O", "O."]: + return True + return False + + + def parse_opts(self, opts): + self.oe = 0 + self.rc = 0 + if not opts: + return + if "O" in opts: + self.oe = 1 + if "." in opts: + self.rc = 1 + + def oe2str(self): + return ['','O'][self.oe==1] + def rc2str(self): + return ['','.'][self.rc==1] + + +class ppc_addi(ppc_mn): + mask_list = [bm_int001110, bm_rt, bm_ra, bm_simm] + namestr = ['ADDI', 'LI'] + + def name2str(self): + if self.ra == 0: + return self.namestr[1] + return self.namestr[0] + + def args2str(self): + args = [] + args.append(reg2str(self.rt)) + if self.ra!=0: + args.append(reg2str(self.ra)) + args.append(imm2str(self.simm)) + return args + + def parse_args(self, args): + self.ra = 0 + self.rt = str2reg(args.pop()) + if len(args)==2: + self.ra = str2reg(args.pop()) + self.simm = str2imm(args.pop()) + + + +class ppc_addic(ppc_addi): + mask_list = [bm_int001100, bm_rt, bm_ra, bm_simm] + namestr = ['ADDIC'] + + +class ppc_addicp(ppc_addi): + mask_list = [bm_int001101, bm_rt, bm_ra, bm_simm] + namestr = ['ADDIC.'] + +class ppc_addis(ppc_addi): + mask_list = [bm_int001111, bm_rt, bm_ra, bm_simm] + namestr = ['ADDIS', 'LIS'] + + +class ppc_adde(ppc_mn): + mask_list = [bm_int011111, bm_rt, bm_ra, bm_int00000, bm_oe, bm_opc9, bm_rc] + namestr = {'ADDME':234, 'ADDZE':202, 'NEG':104, 'SUBFME':232, 'SUBFZE':200} + + mask = {22:bm_set_meta("bm_addeopc",(bm_set,),{"fbits":namestr.values()})} + + strname = dict((x[1], x[0]) for x in namestr.items()) + + do_args = [('rt',reg), ('ra',reg)] + + def name2str(self): + return self.strname[self.opc9] + def str2name(self, n): + self.opc9 = self.namestr[n] + @classmethod + def check_opts(cls, rest): + if rest in ["", ".", "O", "O."]: + return True + return False + + def oe2str(self): + return ['','O'][self.oe==1] + def rc2str(self): + return ['','.'][self.rc==1] + + def parse_opts(self, opts): + self.oe = 0 + self.rc = 0 + if not opts: + return + if "O" in opts: + self.oe = 1 + if "." in opts: + self.rc = 1 + + +class ppc_and(ppc_mn): + mask_list = [bm_int011111, bm_rs, bm_ra, bm_rb, bm_opc10, bm_rc] + namestr = ['ANDC', 'AND', 'EQV', 'NAND', 'NOR', 'ORC', 'OR', 'SLW', 'SRAW', 'SRW', 'XOR'] + namedct = {'AND':28, 'ANDC':60, 'EQV':284, 'NAND':476, 'NOR':124, 'OR':444, 'ORC':412, 'SLW':24, 'SRAW':792, 'SRW':536, 'XOR':316} + mask = {21:bm_set_meta("bm_andopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('ra',reg), ('rs',reg), ('rb',reg)] + + def name2str(self): + return self.strname[self.opc10] + def str2name(self, n): + self.opc10 = self.namedct[n] + @classmethod + def check_opts(cls, rest): + if rest in ["", "."]: + return True + return False + + def rc2str(self): + return ['','.'][self.rc==1] + + + def parse_opts(self, opts): + self.rc = 0 + if not opts: + return + if "." in opts: + self.rc = 1 + + +class ppc_andip(ppc_mn): + mask_list = [bm_int011100, bm_rs, bm_ra, bm_uimm] + namestr = ['ANDI.'] + + do_args = [('ra',reg), ('rs',reg), ('uimm',imm)] + + + def name2str(self): + return self.namestr[0] + + +class ppc_andisp(ppc_andip): + mask_list = [bm_int011101, bm_rs, bm_ra, bm_uimm] + namestr = ['ANDIS.'] + +class ppc_b(ppc_mn): + mask_list = [bm_int010010, bm_li, bm_aa, bm_lk] + namestr = ['B'] + def name2str(self): + return self.namestr[0] + + @classmethod + def check_opts(cls, rest): + if rest in ["", "A", "L", "AL"]: + return True + return False + + def getname(self): + name = "B" + if self.aa: + name+='A' + if self.lk: + name+='L' + return name + + def args2str(self): + args = [] + if type(self.li) in [int, long]: + args.append(imm2str(self.li<<2)) + else: + args.append(str(self.li)) + return args + + def parse_args(self, args): + self.li = str2imm(args.pop())>>2 + + def parse_opts(self, opts): + self.aa = 0 + self.lk = 0 + if not opts: + return + if "A" in opts: + self.aa = 1 + if "L" in opts: + self.lk = 1 + + + + def breakflow(self): + return True + def splitflow(self): + return self.lk + def dstflow(self): + return True + + def getdstflow(self): + if type(self.li) in [int, long]: + li = self.li<<2 + if li &(0x1<<25): + li |=0xFF000000 + li = struct.unpack('L', struct.pack('L', li))[0] + if self.aa: + print "absolute jmp! default abs ad 0" + dst = (li)&0xFFFFFFFF + else: + dst = (self.offset+(li))&0xFFFFFFFF + else: + dst = self.li + return [dst] + + def setdstflow(self, dst): + if len(dst)==0: + return + if len(dst)!=1: + raise ValueError('should be 1 dst') + l = dst[0] + self.li = l.name + + def is_subcall(self): + return self.lk + + def fixdst(self, lbls, my_offset, is_mem = False): + l = self.li + if self.aa: + self.li = lbls[l]>>2 + else: + self.li = (lbls[l]+4-my_offset)>>2 + + + +class ppc_bc(ppc_mn): + mask_list = [bm_int010000, bm_bo, bm_bi, bm_bd, bm_aa, bm_lk] + namestr = ['B'] + all_tests = ['GE', 'LE', 'NE', 'NS', 'LT', 'GT', 'EQ', 'SO'] + def name2str(self): + return self.namestr[0] + + @classmethod + def check_opts(cls, rest): + if not rest: + return False + if rest[0] == 'D': + rest = rest[1:] + if rest[0] == 'Z': + rest = rest[1:] + elif rest.startswith('NZ'): + rest = rest[2:] + else: + return False + elif rest[0] == 'C': + rest = rest[1:] + else: + if len(rest)>1 and rest[:2] in ppc_bc.all_tests: + rest = rest[2:] + else: + return False + if rest in ["", "A", "L", "LA"]: + return True + return False + + def getname(self): + self.bi_parsed = False + name = "B" + if not self.bo &4: + name+="D" + if self.bo & 2: + name+='Z' + else: + name+='NZ' + elif not self.bo &0x10: + index = (self.bo&8)>>1 + index |= self.bi & 3 + name+=ppc_bc.all_tests[index] + self.bi_parsed = True + else: + name+='C' + if self.aa: + name+='A' + if self.lk: + name+='L' + + return name + + + def parse_opts(self, opts): + self.bi_done = False + + self.bo = 0x14 + self.bi = 0 + self.aa = 0 + self.lk = 0 + if not opts: + return + if opts[0] == 'D': + self.bo&=0x1B + opts = opts[1:] + if opts[0] == 'Z': + self.bo|=2 + opts = opts[1:] + elif opts.startswith('NZ'): + self.bo&=0x1d + opts = opts[2:] + elif opts[0] =='C': + pass + else: + if len(opts)>1 and opts[:2] in ppc_bc.all_tests: + self.bi_done = True + index = ppc_bc.all_tests.index(opts[:2]) + inv = index&0x4 + self.bi = index&0x3 + if inv: + self.bo|=8 + else: + self.bo&=0x17 + self.bo &=0xf + opts = opts[2:] + if opts == 'C': + return + if not opts: + return + if opts[0] == 'L': + self.lk = 1 + opts = opts[1:] + if not opts: + return + if not opts: + return + if opts == 'A': + self.aa = 1 + return + + def args2str(self): + args = [] + + if not self.bi_parsed: + if not self.bo & 0x10: + index = (self.bo&8)>>1 + index |= self.bi & 3 + a = ppc_bc.all_tests[index] + + args.append(a) + else: + pass + if self.bi>>2: + args.append(cr2str(self.bi>>2)) + if type(self.bd) in [int, long]: + args.append(imm2str(self.bd<<2)) + else: + args.append(str(self.bd)) + return args + + def parse_args(self, args): + if not self.bi_done: + + if args[-1] in ppc_bc.all_tests: + self.bo &=0xF + + a = args.pop() + index = ppc_bc.all_tests.index(a) + inv = index&0x4 + self.bi = index&0x3 + if inv: + self.bo|=8 + else: + self.bo&=0x17 + else: + self.bo |=0x10 + + pass + + if len(args) >1: + tmp = str2cr(args.pop()) + self.bi|=tmp<<2 + + self.bd = str2imm(args.pop())>>2 + + def breakflow(self): + return True + def splitflow(self): + return True + def dstflow(self): + return True + + def getdstflow(self): + if type(self.bd) in [int, long]: + li = self.bd<<2 + if li &(0x1<<15): + li |=0xFFFF0000 + li = struct.unpack('L', struct.pack('L', li))[0] + if self.aa: + dst = (li)&0xFFFFFFFF + else: + dst = (self.offset+(li))&0xFFFFFFFF + else: + dst = self.bd + return [dst] + + def setdstflow(self, dst): + if len(dst)==0: + return + if len(dst)!=1: + raise ValueError('should be 1 dst') + l = dst[0] + self.bd = l.name + + def is_subcall(self): + return self.lk + + def fixdst(self, lbls, my_offset, is_mem = False): + l = self.bd + if self.aa: + self.bd = lbls[l]>>2 + else: + self.bd = (lbls[l]+4-my_offset)>>2 + + + +class ppc_bctr(ppc_mn): + mask_list = [bm_int010011, bm_bo, bm_bi, bm_int00000, bm_opc10, bm_lk] + namestr = ['BLR', 'BCTR'] + namedct = {'BLR':16, 'BCTR':528} + mask = {21:bm_set_meta("bm_cmpopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + + strname = dict((x[1], x[0]) for x in namedct.items()) + def name2str(self): + return self.strname[self.opc10] + def str2name(self, n): + self.opc10 = self.namedct[n] + + @classmethod + def check_opts(cls, rest): + if not rest: + return True + if rest[0] == 'D': + rest = rest[1:] + if rest[0] == 'Z': + rest = rest[1:] + elif rest.startswith('NZ'): + rest = rest[2:] + else: + return False + elif rest[0] == 'C': + rest = rest[1:] + else: + if len(rest)>1 and rest[:2] in ppc_bc.all_tests: + rest = rest[2:] + else: + return False + if rest in ["", "L"]: + return True + return False + + def getname(self): + self.bi_parsed = False + name = self.name2str() + if not self.bo &4: + name+="D" + if self.bo & 2: + name+='Z' + else: + name+='NZ' + elif not self.bo &0x10: + index = (self.bo&8)>>1 + index |= self.bi & 3 + name+=ppc_bc.all_tests[index] + self.bi_parsed = True + else: + pass + + return name + + + + def parse_opts(self, opts): + self.bi_done = False + + self.bo = 0x14 + self.bi = 0 + self.aa = 0 + self.lk = 0 + if not opts: + return + if opts[0] == 'D': + self.bo&=0x1B + opts = opts[1:] + if opts[0] == 'Z': + self.bo|=2 + opts = opts[1:] + elif opts.startswith('NZ'): + self.bo&=0x1d + opts = opts[2:] + elif opts[0] =='C': + pass + else: + if len(opts)>1 and opts[:2] in ppc_bc.all_tests: + self.bi_done = True + index = ppc_bc.all_tests.index(opts[:2]) + inv = index&0x4 + self.bi = index&0x3 + if inv: + self.bo|=8 + else: + self.bo&=0x17 + self.bo &=0xf + opts = opts[2:] + if opts == 'C': + return + if not opts: + return + if opts[0] == 'L': + self.lk = 1 + opts = opts[1:] + if not opts: + return + if not opts: + return + if opts == 'A': + self.aa = 1 + return + + def args2str(self): + args = [] + if not self.bi_parsed: + if not self.bo & 0x10: + + index = (self.bo&8)>>1 + index |= self.bi & 3 + a = ppc_bc.all_tests[index] + + args.append(a) + else: + pass + if self.bi>>2: + args.append(cr2str(self.bi>>2)) + return args + + def parse_args(self, args): + if not args: + return + if not self.bi_done: + if args[-1] in ppc_bc.all_tests: + self.bo &=0xF + + a = args.pop() + index = ppc_bc.all_tests.index(a) + inv = index&0x4 + self.bi = index&0x3 + if inv: + self.bo|=8 + else: + self.bo&=0x17 + else: + self.bo |=0x10 + + pass + + if len(args) >1: + tmp = str2cr(args.pop()) + self.bi|=tmp<<2 + + + def breakflow(self): + return True + def splitflow(self): + return False + def dstflow(self): + return False + + def getdstflow(self): + return [] + + def setdstflow(self, dst): + pass + def is_subcall(self): + return self.lk + + def fixdst(self, lbls, my_offset, is_mem = False): + pass + + +class ppc_cmp(ppc_mn): + mask_list = [bm_int011111, bm_bf, bm_int00, bm_ra, bm_rb, bm_opc10, bm_int0] + namestr = ['CMPL', 'CMP'] + namedct = {'CMP':0, 'CMPL':32} + mask = {21:bm_set_meta("bm_cmpopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + + strname = dict((x[1], x[0]) for x in namedct.items()) + def name2str(self): + return self.strname[self.opc10] + def str2name(self, n): + self.opc10 = self.namedct[n] + + def args2str(self): + args = [] + if self.bf!=0: + args.append(cr2str(self.bf)) + args.append(reg2str(self.ra)) + args.append(reg2str(self.rb)) + return args + + def parse_args(self, args): + self.bf = 0 + if len(args)==3: + self.bf = str2cr(args.pop()) + self.ra = str2reg(args.pop()) + self.rb = str2reg(args.pop()) + + + +class ppc_cmpli(ppc_mn): + mask_list = [bm_int001010, bm_bf, bm_int00, bm_ra, bm_uimm] + namestr = ['CMPLI'] + + def name2str(self): + return self.namestr[0] + + def args2str(self): + args = [] + if self.bf!=0: + args.append(cr2str(self.bf)) + args.append(reg2str(self.ra)) + args.append(imm2str(self.uimm)) + return args + + def parse_args(self, args): + self.bf = 0 + if len(args)==3: + self.bf = str2cr(args.pop()) + + self.ra = str2reg(args.pop()) + self.uimm = str2imm(args.pop()) + + +class ppc_cmpi(ppc_mn): + mask_list = [bm_int001011, bm_bf, bm_int00, bm_ra, bm_simm] + namestr = ['CMPI'] + + def name2str(self): + return self.namestr[0] + + def args2str(self): + args = [] + if self.bf!=0: + args.append(cr2str(self.bf)) + args.append(reg2str(self.ra)) + args.append(imm2str(self.simm)) + return args + + def parse_args(self, args): + self.bf = 0 + if len(args)==3: + self.bf = str2cr(args.pop()) + self.ra = str2reg(args.pop()) + self.simm = str2imm(args.pop()) + +class ppc_cntlzw(ppc_mn): + mask_list = [bm_int011111, bm_rs, bm_ra, bm_int00000, bm_opc10, bm_rc] + mask = {21:bm_set_meta("bm_cntlzwopc",(bm_set,),{"fbits":[26], 'l':10})} + + namestr = ['CNTLZW'] + + do_args = [('ra',reg), ('rs',reg)] + + def name2str(self): + return self.namestr[0] + + def str2name(self, n): + self.opc10 = 26 + + @classmethod + def check_opts(cls, rest): + if rest in ["", "."]: + return True + return False + + def rc2str(self): + return ['','.'][self.rc==1] + + def parse_opts(self, opts): + self.rc = 0 + if not opts: + return + if "." in opts: + self.rc = 1 + +class ppc_crand(ppc_mn): + mask_list = [bm_int010011, bm_bt, bm_ba, bm_bb, bm_opc10, bm_int0] + namestr = ['CRANDC', 'CRAND', "CREQV", "CRNAND", "CRNOR", "CRORC", "CROR", "CRXOR"] + namedct = {'CRAND':257, 'CRANDC':129, "CREQV":289, "CRNAND":225, "CRNOR":33, "CROR":449, "CRORC":417, + "CRXOR":193} + mask = {21:bm_set_meta("bm_crandopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('bt',crb), ('ba',crb), ('bb',crb)] + + def name2str(self): + return self.strname[self.opc10] + def str2name(self, n): + self.opc10 = self.namedct[n] + + +class ppc_dcb(ppc_crand, ppc_mn): + mask_list = [bm_int011111, bm_int00000, bm_ra, bm_rb, bm_opc10, bm_int0] + namestr = ['DCBTST', 'DCBST', 'DCBF', 'DCBI', 'DCBT', 'DCBZ', 'ICBI'] + namedct = {'DCBTST':246, 'DCBST':54, 'DCBF':86, 'DCBI':470, 'DCBT':278, 'DCBZ':1014, 'ICBI':982} + mask = {21:bm_set_meta("bm_dcbopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('ra',reg), ('rb',reg)] + @classmethod + def check_opts(cls, rest): + if rest in ["", "."]: + return True + return False + + +class ppc_eciw(ppc_crand, ppc_mn): + mask_list = [bm_int011111, bm_rt, bm_ra, bm_rb, bm_opc10, bm_int0] + namestr = ['ECIW', 'ECOW', 'LBZUX', 'LBZX', 'LHAUX', 'LHAX', 'LHBR', 'LHZUX', 'LHZUX', 'LHZX', + 'LSWX', 'STSWX', 'LWARX', 'LWBRX', 'STWBRX', 'LWZX', 'LWZUX', 'STWUX', 'STWX', 'STBUX', + 'STBX', 'STHBRX', 'STHX', 'STHUX'] + namedct = {'ECIW':310, 'ECOW':438, 'LBZUX':119, 'LBZX':87, 'LHAUX':375, 'LHAX':343, 'LHBR':790, + 'LHZUX':311, 'LHZX':279, 'LSWX':533, 'STSWX':661, 'LWARX':20, 'LWBRX':534, 'STWBRX':662, + 'LWZUX':55, 'LWZX':23, 'STWUX':183, 'STWX':151, 'STBUX':247, 'STBX':215, 'STHBRX':918, + 'STHX':407, 'STHUX':439} + mask = {21:bm_set_meta("bm_eciwopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('rt',reg), ('ra',reg), ('rb',reg)] + +class ppc_eieio(ppc_mn): + mask_list = [bm_int011111, bm_int00000, bm_int00000, bm_int00000, bm_opc10, bm_int0] + namestr = ['EIEIO'] + mask = {21:bm_set_meta("bm_eieioopc",(bm_set,),{"fbits":[854], 'l':10})} + + def name2str(self): + return self.namestr[0] + def str2name(self, n): + self.opc10 = 854 + + def __str__(self): + name = self.getname() + return name + + def parse_args(self, args): + pass + +class ppc_isync(ppc_eieio): + mask_list = [bm_int010011, bm_int00000, bm_int00000, bm_int00000, bm_opc10, bm_int0] + namestr = ['ISYNC', 'RFI'] + namedct = {'ISYNC':150, 'RFI':50} + mask = {21:bm_set_meta("bm_isyncopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + strname = dict((x[1], x[0]) for x in namedct.items()) + def name2str(self): + return self.strname[self.opc10] + def str2name(self, n): + self.opc10 = self.namedct[n] + + +class ppc_exts(ppc_crand, ppc_mn): + mask_list = [bm_int011111, bm_rs, bm_ra, bm_int00000, bm_opc10, bm_rc] + namestr = ['EXTSB', 'EXTSH', 'EXTSW'] + namedct = {'EXTSB':954, 'EXTSH':922, 'EXTSW':986} + mask = {21:bm_set_meta("bm_extsopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('ra',reg), ('rs',reg)] + + def rc2str(self): + return ['','.'][self.rc==1] + + def parse_opts(self, opts): + self.rc = 0 + if not opts: + return + if "." in opts: + self.rc = 1 + +class ppc_lbz(ppc_mn): + mask_list = [bm_int100010, bm_rt, bm_ra, bm_simm] + namestr = ['LBZ'] + + do_args = [('rt',reg), ('ra',reg), ('simm',imm)] + + def name2str(self): + return self.namestr[0] + + +class ppc_lbzu(ppc_lbz, ppc_mn): + mask_list = [bm_int100011, bm_rt, bm_ra, bm_uimm] + namestr = ['LBZU'] + + do_args = [('rt',reg), ('ra',reg), ('uimm',imm)] + +class ppc_lha(ppc_lbz): + mask_list = [bm_int101010, bm_rt, bm_ra, bm_simm] + namestr = ['LHA'] + +class ppc_lhau(ppc_lbzu): + mask_list = [bm_int101011, bm_rt, bm_ra, bm_uimm] + namestr = ['LHAU'] + +class ppc_lhz(ppc_lbz): + mask_list = [bm_int101000, bm_rt, bm_ra, bm_simm] + namestr = ['LHZ'] + +class ppc_lhzu(ppc_lbz): + mask_list = [bm_int101001, bm_rt, bm_ra, bm_simm] + namestr = ['LHZU'] + +class ppc_lmw(ppc_lbz): + mask_list = [bm_int101110, bm_rt, bm_ra, bm_simm] + namestr = ['LMW'] + +class ppc_lfd(ppc_lbz): + mask_list = [bm_int110010, bm_rt, bm_ra, bm_simm] + namestr = ['LFD'] + +class ppc_lfdu(ppc_lbz): + mask_list = [bm_int110011, bm_rt, bm_ra, bm_simm] + namestr = ['LFDU'] + +class ppc_lfs(ppc_lbz): + mask_list = [bm_int110000, bm_rt, bm_ra, bm_simm] + namestr = ['LFDS'] + +class ppc_lfsu(ppc_lbz): + mask_list = [bm_int110001, bm_rt, bm_ra, bm_simm] + namestr = ['LFSU'] + +class ppc_lwz(ppc_lbz): + mask_list = [bm_int100000, bm_rt, bm_ra, bm_simm] + namestr = ['LWZ'] + +class ppc_lwzu(ppc_lbz): + mask_list = [bm_int100001, bm_rt, bm_ra, bm_simm] + namestr = ['LWZU'] + +class ppc_stw(ppc_lbz): + mask_list = [bm_int100100, bm_rt, bm_ra, bm_simm] + namestr = ['STW'] + +class ppc_stwu(ppc_lbz): + mask_list = [bm_int100101, bm_rt, bm_ra, bm_simm] + namestr = ['STWU'] + +class ppc_stbu(ppc_lbz): + mask_list = [bm_int100111, bm_rt, bm_ra, bm_simm] + namestr = ['STBU'] + + +class ppc_stb(ppc_lbz): + mask_list = [bm_int100110, bm_rt, bm_ra, bm_simm] + namestr = ['STB'] + +class ppc_stfd(ppc_lbz, ppc_mn): + mask_list = [bm_int110110, bm_rt, bm_ra, bm_simm] + namestr = ['STFD'] + + do_args = [('rt',fpr), ('ra',reg), ('simm',imm)] + +class ppc_stfdu(ppc_lbz, ppc_mn): + mask_list = [bm_int110111, bm_rt, bm_ra, bm_simm] + namestr = ['STFDU'] + + do_args = [('rt',fpr), ('ra',reg), ('simm',imm)] + +class ppc_wi(ppc_crand, ppc_mn): + mask_list = [bm_int011111, bm_rt, bm_ra, bm_nb, bm_opc10, bm_int0] + namestr = ['LSWI', 'STSWI'] + namedct = {'LSWI':597, 'STSWI':725} + mask = {21:bm_set_meta("bm_wiopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('rt',reg), ('ra',reg), ('nb',imm)] + + +class ppc_stfdx(ppc_lbz): + mask_list = [bm_int011111, bm_rt, bm_ra, bm_rb, bm_opc10, bm_int0] + namestr = ['STFDUX', 'STFDX', 'STFIWX', 'STFSUX', 'STFSX'] + namsdct = {'STFDX':727, 'STFDUX':759, 'STFIWX':983, 'STFSX':663, 'STFSUX':695} + mask = {21:bm_set_meta("bm_wiopc",(bm_set,),{"fbits":namsdct.values(), 'l':10})} + strname = dict((x[1], x[0]) for x in namsdct.items()) + + do_args = [('rt',fpr), ('ra',reg), ('simm',imm)] + +class ppc_stfs(ppc_stfd): + mask_list = [bm_int110100, bm_rt, bm_ra, bm_simm] + namestr = ['STFS'] + +class ppc_stfsu(ppc_stfd): + mask_list = [bm_int110101, bm_rt, bm_ra, bm_simm] + namestr = ['STFSU'] + +class ppc_sth(ppc_lbz): + mask_list = [bm_int101100, bm_rt, bm_ra, bm_simm] + namestr = ['STH'] + +class ppc_sthu(ppc_lbz): + mask_list = [bm_int101101, bm_rt, bm_ra, bm_simm] + namestr = ['STHU'] + +class ppc_stmw(ppc_stw): + mask_list = [bm_int101111, bm_rt, bm_ra, bm_simm] + namestr = ['STMW'] + + +class ppc_mcrf(ppc_crand, ppc_mn): + mask_list = [bm_int010011, bm_bf, bm_int00, bm_bfa, bm_int00, bm_int00000, bm_opc10, bm_int0] + namestr = ['MCRFS', 'MCRF' ] + namedct = {'MCRFS':64, 'MCRF':0} + mask = {21:bm_set_meta("bm_mcrfopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('bf',cr), ('bfa',cr)] + +class ppc_mcrxr(ppc_crand, ppc_mn): + mask_list = [bm_int011111, bm_bf, bm_int00, bm_int00000, bm_int00000, bm_opc10, bm_int0] + namestr = ['MCRXR' ] + mask = {21:bm_set_meta("bm_mcrxropc",(bm_set,),{"fbits":[512], 'l':10})} + + do_args = [('bf',cr)] + + + +class ppc_mfcr(ppc_crand, ppc_mn): + mask_list = [bm_int011111, bm_rt, bm_int00000, bm_int00000, bm_opc10, bm_int0] + namestr = ['MFCR', 'MFMSR', 'MTMSR'] + namedct = {'MFCR':19, 'MFMSR':83, 'MTMSR':146} + mask = {21:bm_set_meta("bm_mcrfopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('rt',reg)] + + +class ppc_mffsx(ppc_cntlzw, ppc_mfcr): + mask_list = [bm_int111111, bm_rt, bm_int00000, bm_int00000, bm_opc10, bm_rc] + namestr = ['MFFSR'] + mask = {21:bm_set_meta("bm_mcrxropc",(bm_set,),{"fbits":[583], 'l':10})} + + +class ppc_mtfsb(ppc_exts, ppc_mn): + mask_list = [bm_int111111, bm_bt, bm_int00000, bm_int00000, bm_opc10, bm_rc] #XXX TODO bm_bt doc zarb + namestr = ['MTFSB0', 'MTFSB1'] + namedct = {'MTFSB0':70, 'MTFSB1':38} + mask = {21:bm_set_meta("bm_mcrfopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('bt',crb)] + + +class ppc_mfspr(ppc_crand, ppc_mn): + mask_list = [bm_int011111, bm_rt, bm_spr, bm_opc10, bm_int0] + namestr = ['MFSPR'] + mask = {21:bm_set_meta("bm_mfspropc",(bm_set,),{"fbits":[339, 371], 'l':10})}#XXX TODO ZARB RETRO COMPAT? + + do_args = [('rt',reg), ('spr',spr)] + + def name2str(self): + return self.namestr[0] + def str2name(self, n): + self.opc10 = 339 #XXX TODO default mnemo + +class ppc_mtspr(ppc_mfspr, ppc_mn): + mask_list = [bm_int011111, bm_rt, bm_spr, bm_opc10, bm_int0] + namestr = ['MTSPR'] + mask = {21:bm_set_meta("bm_mcrxropc",(bm_set,),{"fbits":[467], 'l':10})} #XXX TODO ZARB RETRO COMPAT? , 210 + + do_args = [('spr',spr), ('rt',reg)] + def str2name(self, n): + self.opc10 = 467 + +class ppc_mfsr(ppc_crand, ppc_mn): + mask_list = [bm_int011111, bm_rt, bm_int0, bm_sr, bm_int00000, bm_opc10, bm_int0] + namestr = ['MFSR', 'MTSR'] + namedct = {'MFSR':595, 'MTSR':210} + mask = {21:bm_set_meta("bm_mcrfopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('sr',sr), ('rt',reg)] + +class ppc_mulhw(ppc_mn): + mask_list = [bm_int011111, bm_rt, bm_ra, bm_rb, bm_int0, bm_opc9, bm_rc] + namestr = ['MULHWU', 'MULHW'] + namedct = {'MULHW':75, 'MULHWU':11} + mask = {22:bm_set_meta("bm_addopc",(bm_set,),{"fbits":namedct.values()})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('rt',reg), ('ra',reg), ('rb',reg)] + + def name2str(self): + return self.strname[self.opc9] + def str2name(self, n): + self.opc9 = self.namedct[n] + def rc2str(self): + return ['','.'][self.rc==1] + + def parse_opts(self, opts): + self.rc = 0 + if not opts: + return + if "." in opts: + self.rc = 1 + + +class ppc_mulli(ppc_addi): + mask_list = [bm_int000111, bm_rt, bm_ra, bm_simm] + namestr = ['MULLI'] + +class ppc_ori(ppc_addi): + mask_list = [bm_int011000, bm_rt, bm_ra, bm_simm] + namestr = ['ORI'] + +class ppc_oris(ppc_addi): + mask_list = [bm_int011001, bm_rt, bm_ra, bm_simm] + namestr = ['ORIS'] + + +class ppc_rlwimi(ppc_mn): + mask_list = [bm_int010100, bm_rt, bm_ra, bm_sh, bm_mb, bm_me, bm_rc] + namestr = ['RLWIMI'] + + do_args = [('ra',reg), ('rt',reg), ('sh',imm), ('mb',imm), ('me',imm)] + + def name2str(self): + return self.namestr[0] + @classmethod + def check_opts(cls, rest): + if rest in ["", "."]: + return True + return False + + def rc2str(self): + return ['','.'][self.rc==1] + + def parse_opts(self, opts): + self.rc = 0 + if not opts: + return + if "." in opts: + self.rc = 1 + +class ppc_rlwinm(ppc_rlwimi): + mask_list = [bm_int010101, bm_rt, bm_ra, bm_sh, bm_mb, bm_me, bm_rc] + namestr = ['RLWINM'] + +class ppc_rlwnm(ppc_mn): + mask_list = [bm_int010111, bm_rt, bm_ra, bm_rb, bm_mb, bm_me, bm_rc] + namestr = ['RLWNM'] + + do_args = [('ra',reg), ('rt',reg), ('rb',reg), ('mb',imm), ('me',imm)] + + +class ppc_sc(ppc_mn): + mask_list = [bm_int010001, bm_offs, bm_int1, bm_int0] + namestr = ['SC'] + def name2str(self): + return self.namestr[0] + + def args2str(self): + args = [] + args.append(imm2str(self.offs)) + return args + + + + def parse_args(self, args): + self.offs = 0 + pass + + def __str__(self): + name = self.getname() + args = self.args2str() + args = args2str(args) + + return name+" "+args + + +class ppc_srawi(ppc_cntlzw, ppc_mn): + mask_list = [bm_int011111, bm_rs, bm_ra, bm_sh, bm_opc10, bm_rc] + namestr = ['SRAWI'] + mask = {21:bm_set_meta("bm_srawiopc",(bm_set,),{"fbits":[824], 'l':10})} + + do_args = [('ra',reg), ('rs',reg), ('sh',imm)] + + def str2name(self, n): + self.opc10 = 824 + +class ppc_subfic(ppc_addi): + mask_list = [bm_int001000, bm_rt, bm_ra, bm_simm] + namestr = ['SUBFIC'] + + +class ppc_sync(ppc_eieio): + mask_list = [bm_int011111, bm_int00000, bm_int00000, bm_int00000, bm_opc10, bm_int0] + namestr = ['SYNC', 'TLBSYNC'] + namedct = {'SYNC':598, 'TLBSYNC':566} + mask = {21:bm_set_meta("bm_syncopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + strname = dict((x[1], x[0]) for x in namedct.items()) + def name2str(self): + return self.strname[self.opc10] + def str2name(self, n): + self.opc10 = self.namedct[n] + + +class ppc_tlb(ppc_sync, ppc_mn): + mask_list = [bm_int011111, bm_int00000, bm_int00000, bm_rb, bm_opc10, bm_int0] + namestr = ['TLBIE', 'TLBID', 'TLBLI'] + namedct = {'TLBIE':306, 'TLBLD':978, 'TLBLI':1010} + mask = {22:bm_set_meta("bm_addopc",(bm_set,),{"fbits":namedct.values()})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('rb',reg)] + +class ppc_xori(ppc_addi): + mask_list = [bm_int011010, bm_rt, bm_ra, bm_simm] + namestr = ['XORI'] + +class ppc_xoris(ppc_addi): + mask_list = [bm_int011011, bm_rt, bm_ra, bm_simm] + namestr = ['XORIS'] + + +class ppc_tw(ppc_crand, ppc_mn): + mask_list = [bm_int011111, bm_to, bm_ra, bm_rb, bm_opc10, bm_int0] + namestr = ['TW'] + namedct = {'TW':4} + mask = {21:bm_set_meta("bm_wiopc",(bm_set,),{"fbits":[4], 'l':10})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('to',imm), ('ra',reg), ('rb',reg)] + +class ppc_twi(ppc_mn): + mask_list = [bm_int000011, bm_to, bm_ra, bm_simm] + namestr = ['TWI'] + + do_args = [('to',imm), ('ra',reg), ('simm',imm)] + + def name2str(self): + return self.namestr[0] + + + +#FPU + +class ppc_fabs(ppc_and, ppc_mn): + mask_list = [bm_int111111, bm_frt, bm_int00000, bm_frb, bm_opc10, bm_rc] + namestr = ['FABS', 'FCTIWZ', 'FCTIW', 'FMR', 'FNABS', 'FNEG', 'FRSP'] + namedct = {'FABS':264, 'FCTIWZ':15, 'FCTIW':14, 'FMR':72, 'FMABS':136, 'FNEG':40, 'FRSP':12} + mask = {21:bm_set_meta("bm_addopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('frt',fpr), ('frb',fpr)] + + +class ppc_fdiv(ppc_fabs, ppc_mn): + mask_list = [bm_int111111, bm_frt, bm_fra, bm_frb, bm_int00000, bm_opc5, bm_rc] + namestr = ['FDIV', 'FSUB', 'FADD'] + namedct = {'FDIV':18, 'FSUB':20, 'FADD':21} + mask = {26:bm_set_meta("bm_fdivopc",(bm_set,),{"fbits":namedct.values(), 'l':5})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('frt',fpr), ('fra',fpr), ('frb',fpr)] + + def name2str(self): + return self.strname[self.opc5] + def str2name(self, n): + self.opc5 = self.namedct[n] + +class ppc_fcmp(ppc_fabs, ppc_mn): + mask_list = [bm_int111111, bm_bf, bm_int00, bm_fra, bm_frb, bm_opc10, bm_rc] + namestr = ['FCMPO', 'FCMPU'] + namedct = {'FCMPO':32, 'FCMPU':0} + mask = {21:bm_set_meta("bm_fcmpopc",(bm_set,),{"fbits":namedct.values(), 'l':10})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('bf',cr), ('fra',fpr), ('frb',fpr)] + + +class ppc_fdivs(ppc_fdiv): + mask_list = [bm_int111011, bm_frt, bm_fra, bm_frb, bm_int00000, bm_opc5, bm_rc] + namestr = ['FDIVS', 'FSUBS', 'FADDS'] + namedct = {'FDIVS':18, 'FSUBS':20, 'FADDS':21} + mask = {26:bm_set_meta("bm_fdivsopc",(bm_set,),{"fbits":namedct.values(), 'l':5})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + +class ppc_fmadd(ppc_fdiv, ppc_mn): + mask_list = [bm_int111111, bm_frt, bm_fra, bm_frb, bm_frc, bm_opc5, bm_rc] + namestr = ['FMADD', 'FMSUB', 'FNMADD', 'FNMSUB', 'FSEL'] + namedct = {'FMADD':29, 'FMSUB':28, 'FNMADD':31, 'FNMSUB':30, 'FSEL':23} + mask = {26:bm_set_meta("bm_fmaddopc",(bm_set,),{"fbits":namedct.values(), 'l':5})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('frt',fpr), ('fra',fpr), ('frb',fpr), ('frc',fpr)] + +class ppc_fmadds(ppc_fdiv): + mask_list = [bm_int111011, bm_frt, bm_fra, bm_frb, bm_frc, bm_opc5, bm_rc] + namestr = ['FMADDS', 'FMSUBS', 'FNMADDS', 'FNMSUBS'] + namedct = {'FMADDS':29, 'FMSUBS':28, 'FNMADDS':31, 'FNMSUBS':30} + mask = {26:bm_set_meta("bm_fmaddsopc",(bm_set,),{"fbits":namedct.values(), 'l':5})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + +class ppc_fmul(ppc_fdiv, ppc_mn): + mask_list = [bm_int111111, bm_frt, bm_fra, bm_int00000, bm_frc, bm_opc5, bm_rc] + namestr = ['FMUL'] + namedct = {'FMUL':25} + mask = {26:bm_set_meta("bm_fmulopc",(bm_set,),{"fbits":namedct.values(), 'l':5})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('frt',fpr), ('fra',fpr), ('frc',fpr)] + + +class ppc_fmuls(ppc_fmul): + mask_list = [bm_int111011, bm_frt, bm_fra, bm_int00000, bm_frc, bm_opc5, bm_rc] + namestr = ['FMULS'] + namedct = {'FMULS':25} + mask = {26:bm_set_meta("bm_fmaddsopc",(bm_set,),{"fbits":namedct.values(), 'l':5})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + +class ppc_fres(ppc_fdiv, ppc_mn): + mask_list = [bm_int111011, bm_frt, bm_int00000, bm_frb, bm_int00000, bm_opc5, bm_rc] + namestr = ['FRES'] + namedct = {'FRES':24} + mask = {26:bm_set_meta("bm_fmulopc",(bm_set,),{"fbits":namedct.values(), 'l':5})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + do_args = [('frt', fpr),('frb', fpr)] + + +class ppc_frsqrte(ppc_fres): + mask_list = [bm_int111111, bm_frt, bm_fra, bm_int00000, bm_frc, bm_opc5, bm_rc] + namestr = ['FRSQRTE'] + namedct = {'FRSQRTE':26} + mask = {26:bm_set_meta("bm_fmaddsopc",(bm_set,),{"fbits":namedct.values(), 'l':5})} + strname = dict((x[1], x[0]) for x in namedct.items()) + + +#order is important +tab_mn = [ppc_addi, ppc_ori, ppc_oris, ppc_xori, ppc_xoris, ppc_addic, ppc_addicp, ppc_addis, ppc_adde, ppc_and, + ppc_andip, ppc_andisp, ppc_bctr, ppc_bc, ppc_b, ppc_cmpli, ppc_cmpi, ppc_cmp, ppc_cntlzw, + ppc_crand, ppc_dcb, ppc_eciw, ppc_eieio, ppc_exts, ppc_isync, ppc_lfsu, ppc_lfdu, ppc_lfs, ppc_lfd, ppc_lbzu, + ppc_lbz, ppc_lhau, ppc_lha, ppc_lhzu, ppc_lhz, ppc_lmw, ppc_wi, ppc_lwzu, + ppc_lwz, ppc_stwu, ppc_stw, ppc_stfdu, ppc_stfd, ppc_stfdx, ppc_stfsu, + ppc_stfs, ppc_sthu, ppc_sth, ppc_stmw, ppc_stbu, ppc_stb, ppc_mcrxr, ppc_mcrf, + ppc_mffsx, ppc_mfspr, ppc_mfcr, ppc_mtfsb, ppc_mtspr, ppc_mfsr, ppc_mulhw, ppc_mulli, + ppc_rlwimi, ppc_rlwinm, ppc_rlwnm, ppc_sc, ppc_srawi, ppc_subfic, + ppc_sync, ppc_tlb, ppc_add, ppc_twi, ppc_tw, + + ppc_fabs, ppc_fcmp, ppc_fdivs, ppc_fdiv, ppc_fmadds, ppc_fmadd, ppc_fmuls, ppc_fmul, + ppc_frsqrte, ppc_fres] + + + +if __name__ == "__main__": + + import struct + + + for op in [0x7D4A5214, 0x7FAA4A14, 0x7D615A14]: + + m = ppc_mn(op) + print m + + + txt = """ + ADD R10, R10, R10 + ADDO. R10, R10, R10 + ADD R29, R10, R9 + ADD R11, SP, R11 + LI R10, 0x23 + LIS R10, 0x23 + ADDIS R10, R0, 0x23 + ADDI R10, R0, 0x23 + ADDI R0, R11, -0x7 + ADDIC R8, R6, -1 + ADDIC. R5, R5, -1 + ADDIS R4, R31, 1 + ADDME R7, R5 + AND R11, R11, R4 + ANDC R11, R11, R3 + AND. R5, R5, R4 + ANDI. R30, R30, 0x2e00 + ANDIS. R11, R3, 0x8000 + BA 0x1337 + BL 0x1337 + B 0x3 + CMPL CR0, R3, R4 + CMPL R3, R4 + CMP CR0, R3, R4 + CMP R3, R4 + CMPLI CR0, R0, 0x18 + CMPLI R0, 0x18 + CMPI CR0, R3, 1 + CMPI CR0, R28, -1 + CMPLI CR5, R11, 3 + CNTLZW R4, R9 + CRAND CR0_EQ, CR1_EQ, CR2_EQ + CRNOR CR5_LT, CR5_LT, CR6_LT + DCBT R4, R5 + DIVWU R0, R29, R10 + DIVW R0, R12, R11 + ECIW R0, R0, R0 + EIEIO + EXTSH R11, R3 + ISYNC + LBZ R11, R11, 0x70 + LBZX R12, R3, R12 + LHA R3, R31, 2 + LHAU R3, R31, 2 + LHZ R3, R5, 0xA + LHZX R12, R4, R12 + LMW R27, SP, 0xC + LSWI R7, R12, 4 + STSWI R7, R11, 4 + LWZ R0, SP, 0xC + STW R0, SP, 8 + STWU SP, SP, -0x10 + LWZX R9, R3, R11 + STWX R7, R9, R8 + STBX R12, R31, R4 + STFD FP31, SP, 0x28 + STFS FP1, R8, 4 + STH R4, R6, 2 + STHX R11, R6, R7 + STMW R27, SP, 0xC + MCRF CR0, CR1 + MFSR SR1, R0 + MTSR SR1, R0 + MULHWU R30, R12, R27 + MULLI R9, R25, 0x90 + MULLW R10, R26, R10 + ORI R4, R4, 0x60b6 + ORIS R3, R3, -1 + RFI + RLWINM R30, R28, 26, 22, 25 + RLWINM. R10, R3, 0, 21, 21 + SLW R6, R6, R12 + SRAWI R11, R11, 1 + STB R12, SP, 0xC + SUBF R4, R5, R4 + SUBFE R11, R30, R5 + SUBFIC R3, R7, 0xFF + SUBFZE R30, R30 + SYNC + XOR R6, R12, R11 + XORIS R11, R11, 0x8000 + FCTIWZ FP0, FP13 + FNEG FP3, FP1 + FMR FP1, FP31 + FRSP FP1, FP13 + FDIVS FP1, FP2, FP1 + FSUB FP13, FP13, FP12 + FSUBS FP11, FP2, FP11 + FADDS FP1, FP13, FP11 + FMADD FP1, FP2, FP3, FP4 + FMADD. FP1, FP2, FP3, FP4 + FMULS FP13, FP13, FP11 + FRES FP1, FP2 + BGE 0x10 + BLE 0x10 + BNE 0x10 + BNS 0x10 + BLT 0x10 + BGT 0x10 + BEQ 0x10 + BSO 0x10 + BGE CR1, 0x10 + BDNZ 0x10 + BDNZ LE, 0x10 + BDNZ LE, CR1, 0x10 + MFSPR R0, LR + MTSPR LR, R0 + BC LE, CR1, 0x10 + BLE CR1, 0x10 + BLR + BC 0x10 + FCMPU CR1, FP1, FP3 + MTFSB0 CR1_LT + TW 1, R3, R4 + TWI 3, R4, 8 + SC""" + + + # UNDEF 0x1337, 1 + + txt = txt.split('\n')[1:] + for t in txt: + print "___%s___"%t + op1 = ppc_mn.asm(t)[0] + h = struct.unpack('>L', op1) + print "bin: %.8X"%h + m = ppc_mn.dis(op1) + print "dis:", str(m) + token_a = [x for x in shlex.shlex(t)] + token_b = [x for x in shlex.shlex(str(m))] + token_a = filter(lambda x:not x in ['-', ',', 'CR0'] and not is_imm(x), token_a) + token_b = filter(lambda x:not x in ['-', ',', 'CR0'] and not is_imm(x), token_b) + print token_a + print token_b + + op2 = ppc_mn.asm(str(m))[0] + h = struct.unpack('>L', op2) + print "%.8X"%h + if op1 !=op2 or (token_a != token_b and not token_b[0] in ['BLE', 'ADDI', 'LI', 'ADDIS', 'LIS']): + raise ValueError('bug in self test', t) + + diff --git a/miasm/core/__init__.py b/miasm/core/__init__.py new file mode 100644 index 00000000..1fffa08b --- /dev/null +++ b/miasm/core/__init__.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +#__all__ = ['ia32_reg'] diff --git a/miasm/core/asmbloc.py b/miasm/core/asmbloc.py new file mode 100644 index 00000000..7b92fdb6 --- /dev/null +++ b/miasm/core/asmbloc.py @@ -0,0 +1,1364 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +import re +import logging +import shlex +import struct +from numpy import uint8, uint16, uint32, uint64, int8, int16, int32, int64 +from collections import defaultdict +log_asmbloc = logging.getLogger("asmbloc") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s")) +log_asmbloc.addHandler(console_handler) +log_asmbloc.setLevel(logging.WARN) + +tab_int_size = {int8:8, + uint8:8, + int16:16, + uint16:16, + int32:32, + uint32:32, + int64:64, + uint64:64 + } + + +class asm_label: + def __init__(self, name = "", offset = None): + + self.next = "next" + self.noattrib = "noattrib" + self.fixedblocs = False + if type(name) in [int, long]+tab_int_size.keys(): + name = "loc_%.8X"%int(name) + self.name = name + self.attrib = self.noattrib + if offset == None: + self.offset = offset + else: + self.offset = int(offset) + + def __str__(self): + out = "%s: %s"%(self.name, str(self.offset)) + return out + def __repr__(self): + rep = '<asmlabel ' + if self.name: + rep+=repr(self.name)+' ' + rep+='>' + return rep + +class asm_raw: + def __init__(self, raw = ""): + self.raw = raw + def __str__(self): + return repr(self.raw) + + +class asm_constraint: + c_to = "c_to" + c_next = "c_next" + + def __init__(self, label = None, c_t = c_to): + self.label = label + self.c_t = c_t + + def __str__(self): + return str(self.label)+'\t'+str(self.c_t) + + +class asm_bloc: + def __init__(self, label=None): + self.bfrom = [] + self.bto = [] + self.lines = [] + self.label = label + self.age = 0 + + def __str__(self): + out = str(self.label)+"\n" + out+="from ->" + for l in self.bfrom: + out+="%.8X"%l+" " + out+="\n" + for l in self.lines: + out+=str(l)+'\n' + out+="to ->" + for l in self.bto: + if l == None: + out+="Unknown? " + else: + out+=str(l)+" " + return out + + + def addline(self, l): + self.lines.append(l) + def addfrom(self, l): + self.bfrom.append(l) + def addto(self, l): + self.bto.append(l) + + + def split(self, offset, l): + i = -1 + offsets = [x.offset for x in self.lines] + if not l.offset in offsets: + log_asmbloc.warning( 'cannot split bloc at %X middle instruction? default middle'%offset) + offsets.sort() + + return None + new_bloc = asm_bloc(l) + i = offsets.index(offset) + self.lines, new_bloc.lines = self.lines[:i],self.lines[i:] + new_bloc.bto = self.bto + c = asm_constraint(l, asm_constraint.c_next) + self.bto = [c] + return new_bloc + + def get_range(self): + if len(self.lines): + return self.lines[0].offset, self.lines[-1].offset + else: + return 0,0 + def get_offsets(self): + return [x.offset for x in self.lines] + +class asm_symbol_pool: + def __init__(self): + self.s = {} + self.s_offset = {} + + + def remove(self, l): + if l.name in self.s: + del(self.s[l.name]) + if l.offset != None and l.offset in self.s_offset: + del(self.s_offset[l.offset]) + + def add(self, l): + if l.name in self.s: + fdsf + self.s[l.name] = l + self.s_offset[l.offset] = l + + def del_offset(self, l = None): + if l: + if l.offset in self.s_offset: + del(self.s_offset[l.offset]) + l.offset = None + else: + self.s_offset = {} + for l in self.s: + self.s[l].offset = None + + def getby_offset(self, offset): + if offset in self.s_offset: + return self.s_offset[offset] + return None + + def getby_name(self, name): + if name in self.s: + return self.s[name] + return None + + def getby_name_create(self, name): + if name in self.s: + return self.s[name] + else: + l = asm_label(name) + self.add(l) + return l + + def getby_offset_create(self, offset): + if offset in self.s_offset: + return self.s_offset[offset] + else: + l = asm_label(offset, offset) + self.add(l) + return l + + + def __str__(self): + return reduce(lambda x,y: x+str(y)+'\n', [self.s[l] for l in self.s], "") + + + + +def dis_bloc(mnemo, pool_bin, cur_bloc, offset, job_done, symbol_pool, dont_dis = [], + follow_call = False, patch_instr_symb = True, dontdis_retcall = False, + lines_wd = None, amode="u32", sex=0, dis_bloc_callback = None, dont_dis_nulstart_bloc = False): + pool_bin.offset = offset + + lines_cpt = 0 + + while True: + lines_cpt+=1 + if lines_wd !=None and lines_cpt>lines_wd: + log_asmbloc.warning( "lines watchdog reached at %X"%int(offset)) + offsets_to_dis = [] + break + + if pool_bin.offset in dont_dis: + l = symbol_pool.getby_offset_create(pool_bin.offset) + c = asm_constraint(l, asm_constraint.c_next) + cur_bloc.bto = [c] + offsets_to_dis = [pool_bin.offset] + break + + if pool_bin.offset in job_done: + #if not pool_bin.offset in symbol_pool.s_offset: + # # XXX bug: we start dis in middle of bb + if pool_bin.offset in symbol_pool.s_offset: + l = symbol_pool.s_offset[pool_bin.offset] + c = asm_constraint(l, asm_constraint.c_next) + cur_bloc.bto = [c] + offsets_to_dis = [pool_bin.offset] + break + + job_done.add(pool_bin.offset) + log_asmbloc.debug("dis at %X"%int(pool_bin.offset)) + if lines_cpt <=1 and dont_dis_nulstart_bloc: + off_i = pool_bin.offset + c = pool_bin.readbs() + pool_bin.offset = off_i + if c == "\x00": + offsets_to_dis = [] + log_asmbloc.warning( "bloc start with nul %X"%int(off_i)) + break + + instr = mnemo.dis(pool_bin, amode, sex) + + + if instr == None: + log_asmbloc.warning( "cannot disasm at %X"%int(offset)) + cur_bloc.bto = [] + offsets_to_dis = [] + break + + log_asmbloc.debug(instr) + log_asmbloc.debug(instr.m) + log_asmbloc.debug(instr.arg) + + cur_bloc.addline(instr) + if not instr.breakflow(): + continue + + + if instr.splitflow() and not (instr.is_subcall() and dontdis_retcall): + n = instr.getnextflow() + l = symbol_pool.getby_offset_create(n) + c = asm_constraint(l, asm_constraint.c_next) + cur_bloc.bto.append(c) + + if instr.dstflow(): + dst = instr.getdstflow() + dstn = [] + for d in dst: + if type(d) in [int, long]+tab_int_size.keys(): + d = symbol_pool.getby_offset_create(d) + dstn.append(d) + dst = dstn + if len(dst) == 1: + if isinstance(dst[0], asm_label): + instr.setdstflow(dst) + if (not instr.is_subcall()) or follow_call: + cur_bloc.bto+=[asm_constraint(x, asm_constraint.c_to) for x in dst] + offsets_to_dis = [x.label.offset for x in cur_bloc.bto if isinstance(x.label, asm_label)] + break + + if dis_bloc_callback != None: + dis_bloc_callback(cur_bloc, offsets_to_dis, symbol_pool) + return offsets_to_dis + + + +def dis_i(mnemo, pool_bin, offset, symbol_pool): + symbol_pool = asm_symbol_pool() + dum_l = symbol_pool.getby_offset_create(offset) + dum_b = asm_bloc(dum_l) + + dis_bloc(mnemo, pool_bin, dum_b, offset, set(), symbol_pool, lines_wd = 1) + if not dum_b.lines: + return None + return dum_b.lines[0] + +def split_bloc(all_bloc, symbol_pool, more_ref = None, dis_bloc_callback = None): + i = -1 + err = False + if not more_ref: + more_ref = [] + more_ref = [symbol_pool.s_offset[x] for x in more_ref] + while i<len(all_bloc)-1: + i+=1 + for n in [x.label for x in all_bloc[i].bto if isinstance(x.label, asm_label)]+ more_ref: + if n == None: + continue + n = n.offset + j = -1 + while j<len(all_bloc)-1 and not err: + j+=1 + a,b = all_bloc[j].get_range() + if n >a and n <=b: + l = symbol_pool.getby_offset_create(n) + new_b = all_bloc[j].split(n,l) + + log_asmbloc.debug("split bloc %x"%n) + if new_b== None: + log_asmbloc.error("cannot split %x!!"%n) + err = True + break + if dis_bloc_callback: + dis_bloc_callback(new_b, [x.label.offset for x in new_b.bto if isinstance(x.label, asm_label)], + symbol_pool) + all_bloc.append(new_b) + if err: + break + return all_bloc + +def dis_bloc_all(mnemo, pool_bin, offset, job_done, symbol_pool, dont_dis = [], + follow_call = False, patch_instr_symb = True, dontdis_retcall = False, + amode="u32", sex=0 , bloc_wd = None, lines_wd = None, all_bloc = None, + dis_bloc_callback = None, dont_dis_nulstart_bloc = False): + log_asmbloc.info("dis bloc all") + if all_bloc == None: + all_bloc = [] + todo = [offset] + + bloc_cpt = 0 + while len(todo): + bloc_cpt+=1 + if bloc_wd !=None and bloc_cpt>bloc_wd: + log_asmbloc.debug( "blocs watchdog reached at %X"%int(offset)) + break + + n = int(todo.pop(0)) + if n in job_done: + continue + if n == None: + continue + + if n in dont_dis: + continue + dd_flag = False + for dd in dont_dis: + if not isinstance(dd, tuple): + continue + dd_a, dd_b = dd + if dd_a <= n < dd_b: + dd_flag = True + break + if dd_flag: + continue + + l = symbol_pool.getby_offset_create(n) + cur_bloc = asm_bloc(l) + todo += dis_bloc(mnemo, pool_bin, cur_bloc, n, job_done, symbol_pool, dont_dis, follow_call, patch_instr_symb, dontdis_retcall, amode=amode, sex=sex, dis_bloc_callback = dis_bloc_callback, lines_wd = lines_wd, dont_dis_nulstart_bloc = dont_dis_nulstart_bloc) + all_bloc.append(cur_bloc) + + + return split_bloc(all_bloc, symbol_pool, dis_bloc_callback = dis_bloc_callback) + + #return all_bloc + + + +def bloc2graph(blocs, label = False, lines = True): + #rankdir=LR; + out = """ +digraph asm_graph { +size="80,50"; +node [ +fontsize = "16", +shape = "box" +]; +""" + for b in blocs: + out+='%s [\n'%b.label.name + out+='label = "' + + out+=b.label.name+"\\l\\\n" + if lines: + for l in b.lines: + if label: + out+="%.8X "%l.offset + out+="%s\\l\\\n"%l + out+='"\n];\n' + + for b in blocs: + for n in b.bto: + if isinstance(n.label, asm_label): + out+='%s -> %s [ label = "%s" ];\n'%(b.label.name, n.label.name, n.c_t) + out+="}" + return out + +#this function group asm blocs with next constraints +def group_blocs(all_bloc): + log_asmbloc.info('group_blocs') + #group adjacent blocs + rest = all_bloc[:] + + groups_bloc = {} + d = dict([(x.label,x) for x in rest]) + log_asmbloc.debug([str(x.label) for x in rest]) + + while rest: + b = [rest.pop()] + #find recursive son + fini =False + while not fini: + fini=True + for c in b[-1].bto: + if c.c_t != asm_constraint.c_next: + continue + if d[c.label] in rest: + b.append(d[c.label]) + rest.remove(d[c.label]) + fini =False + break + #check if son in group: + found_in_group = False + for c in b[-1].bto: + if c.c_t != asm_constraint.c_next: + continue + if c.label in groups_bloc: + b+=groups_bloc[c.label] + del(groups_bloc[c.label]) + groups_bloc[b[0].label] = b + found_in_group = True + break + + if not found_in_group: + groups_bloc[b[0].label] = b + + #create max label range for bigbloc + for l in groups_bloc: + l.total_max_l = reduce(lambda x,y: x+y.blen_max, groups_bloc[l], 0) + log_asmbloc.debug(("offset totalmax l", l.offset, l.total_max_l)) + if type(l.offset) in [int, long]+tab_int_size.keys(): + hof = hex(int(l.offset)) + else: + hof = l.name + log_asmbloc.debug(("offset totalmax l", hof, l.total_max_l)) + + return groups_bloc + + +def gen_free_space_intervals(f, dont_erase = []): + interval = {} + last_offset = 0xFFFFFFFF + offset_label = dict([(x.offset_free,x) for x in f]) + offset_label_order = offset_label.keys() + offset_label_order.sort() + offset_label_order.append(last_offset) + offset_label_order.reverse() + + + unfree_stop= 0L + while len(offset_label_order)>1: + offset = offset_label_order.pop() + offset_end = offset+f[offset_label[offset]] + prev = 0 + if unfree_stop>offset_end: + space = 0 + else: + space = offset_label_order[-1]-offset_end + if space <0: + space = 0 + interval[offset_label[offset]] = space + if offset_label_order[-1] in offset_label: + prev = offset_label[offset_label_order[-1]] + prev = f[prev] + + interval[offset_label[offset]] = space + + unfree_stop = max(unfree_stop, offset_end, offset_label_order[-1]+prev) + + return interval + +def add_dont_erase(f, dont_erase = []): + for a,b in dont_erase: + l = asm_label(a, a) + l.offset_free = a + f[l] = b-a + return + + +def del_dis_offset(all_bloc, symbol_pool): + for b in all_bloc: + symbol_pool.s[b.label.name].offset = None + + + +def gen_non_free_mapping(group_bloc, dont_erase = []): + non_free_mapping = {} + non_free_mappingb = {} + #calculate free space for bloc placing + for g in group_bloc: + rest_len = 0 + g.fixedblocs = False + #if a label in the group is fixed + diff_offset = 0 + for b in group_bloc[g]: + if not type(b.label.offset) in [int, long]+tab_int_size.keys(): + diff_offset+=b.blen_max + continue + g.fixedblocs = True + g.offset_free = b.label.offset - diff_offset + break + if g.fixedblocs: + non_free_mapping[g] = g.total_max_l + + log_asmbloc.debug("non free bloc:") + log_asmbloc.debug(non_free_mapping) + add_dont_erase(non_free_mapping, dont_erase) + log_asmbloc.debug("non free more:") + log_asmbloc.debug(non_free_mapping) + return non_free_mapping + + + +# if one bloc is fixed in the bloc list, this function +# will fix other blocs around this one. +def fix_bloc_around_anchored_bloc(unr_bloc): + + l2b = {} + for b in unr_bloc: + l2b[b.label] = b + + b_done = set() + b_todo = set() + b_rest = set() + for l in unr_bloc: + if l.label.fixedblocs: + b_todo.add(l.label) + else: + b_rest.add(l.label) + print b_todo + print b_rest + + while b_todo: + b = b_todo.pop() + print 'testing ', b + b_done.add(b) + i = unr_bloc.index(l2b[b]) + if i >0 and unr_bloc[i-1].label in b_rest: + unr_bloc[i-1].label.offset = [b, unr_bloc[i-1], -1] + unr_bloc[i-1].fixedblocs = True + b_todo.add(unr_bloc[i-1].label) + b_rest.remove(unr_bloc[i-1].label) + if i < len(unr_bloc)-1 and unr_bloc[i+1].label in b_rest: + unr_bloc[i+1].label.offset = [b, unr_bloc[i], 1] + unr_bloc[i+1].fixedblocs = True + b_todo.add(unr_bloc[i+1].label) + b_rest.remove(unr_bloc[i+1].label) + + + +# place all asmblocs, ordered +# XXX WARNING, doesn't use dont erase arg!! +def resolve_symbol_linear(bloc_list, group_bloc, dont_erase = []): + print bloc_list + log_asmbloc.info('resolve_symbol') + log_asmbloc.info(str(dont_erase)) + + non_free_mapping = gen_non_free_mapping(group_bloc, dont_erase) + + + + + unr_bloc = [] + + for l in bloc_list: + unr_bloc+=group_bloc[l] + + l2b = {} + for b in unr_bloc: + l2b[b.label] = b + + + # first, link grouped bloc around fixed labels + for g in group_bloc.values(): + fix_bloc_around_anchored_bloc(g) + + + + + b_done = set() + b_todo = set() + b_rest = set() + for l in unr_bloc: + if l.label in bloc_list and l.label.fixedblocs: + b_todo.add(l.label) + else: + b_rest.add(l.label) + print b_todo + print b_rest + + while b_todo: + b = b_todo.pop() + print 'testing ', b + b_done.add(b) + i = unr_bloc.index(l2b[b]) + if i >0 and unr_bloc[i-1].label in b_rest: + unr_bloc[i-1].label.offset = [b, unr_bloc[i-1], -1] + b_todo.add(unr_bloc[i-1].label) + b_rest.remove(unr_bloc[i-1].label) + if i < len(unr_bloc)-1 and unr_bloc[i+1].label in b_rest: + unr_bloc[i+1].label.offset = [b, unr_bloc[i], 1] + b_todo.add(unr_bloc[i+1].label) + b_rest.remove(unr_bloc[i+1].label) + print b_todo + print b_rest + print b_done + + return [(x,0) for x in unr_bloc] + + bloc_list = [] + unr_bloc = reduce(lambda x,y: x+group_bloc[y], group_bloc, []) + ending_ad = [] + + free_interval = gen_free_space_intervals(non_free_mapping) + log_asmbloc.debug(free_interval) + + + +#place all asmblocs +def resolve_symbol(group_bloc, dont_erase = []): + log_asmbloc.info('resolve_symbol') + log_asmbloc.info(str(dont_erase)) + + bloc_list = [] + unr_bloc = reduce(lambda x,y: x+group_bloc[y], group_bloc, []) + ending_ad = [] + + non_free_mapping = gen_non_free_mapping(group_bloc, dont_erase) + free_interval = gen_free_space_intervals(non_free_mapping) + log_asmbloc.debug(free_interval) + + + + #first big ones + g_tab = [(x.total_max_l,x) for x in group_bloc] + g_tab.sort() + g_tab.reverse() + g_tab = [x[1] for x in g_tab] + + #g_tab => label of grouped blov + #group_bloc => dict of grouped bloc labeled-key + + #first, near callee placing algo + for g in g_tab: + if g.fixedblocs: + continue + finish = False + for x in group_bloc: + if not x in free_interval.keys(): + continue + if free_interval[x]<g.total_max_l: + continue + + for b in group_bloc[x]: + for c in b.bto: + if c.label == g: + tmp = free_interval[x]-g.total_max_l + log_asmbloc.debug("consumed %d rest: %d"%(g.total_max_l, int(tmp))) + free_interval[g] = tmp + del(free_interval[x]) + + g.offset = [group_bloc[x][-1].label, group_bloc[x][-1], 1] + g.fixedblocs = True + finish = True + break + if finish: + break + if finish: + break + + #second, bigger in smaller algo + for g in g_tab: + if g.fixedblocs: + continue + #chose smaller free_interval first + k_tab = [(free_interval[x],x) for x in free_interval] + k_tab.sort() + k_tab = [x[1] for x in k_tab] + #choose free_interval + for k in k_tab: + if g.total_max_l>free_interval[k]: + continue + g.offset = [group_bloc[k][-1].label, group_bloc[k][-1], 1] + tmp = free_interval[k]-g.total_max_l + log_asmbloc.debug("consumed %d rest: %d"%(g.total_max_l, int(tmp))) + free_interval[g] = tmp + del(free_interval[k]) + + g.fixedblocs = True + break + + while unr_bloc: + #propagate know offset + resolving = False + i = 0 + while i < len(unr_bloc): + if unr_bloc[i].label.offset == None: + i+=1 + continue + resolving = True + log_asmbloc.info("bloc %s resolved"%unr_bloc[i].label) + bloc_list.append((unr_bloc[i],0)) + + g_found = None + for g in g_tab: + if unr_bloc[i] in group_bloc[g]: + if g_found!=None: + raise ValueError('blocin multiple group!!!') + g_found = g + my_group = group_bloc[g_found] + + index = my_group.index(unr_bloc[i]) + if index>0 and my_group[index-1] in unr_bloc: + my_group[index-1].label.offset = [unr_bloc[i].label, unr_bloc[i-1], -1] + if index <len(my_group)-1 and my_group[index+1] in unr_bloc: + my_group[index+1].label.offset = [unr_bloc[i].label, unr_bloc[i], 1] + + del unr_bloc[i] + + if not resolving: + log_asmbloc.warn("cannot resolve symbol! (no symbol fix found)") + else: + continue + + for g in g_tab: + print g + if g.fixedblocs: + print "fixed" + else: + print "not fixed" + raise ValueError('enable to fix bloc') + + return bloc_list + + +def calc_symbol_offset(symbol_pool): + keys = symbol_pool.s.keys() + for l in symbol_pool.s: + symbol_pool.s[l].offset_g = symbol_pool.s[l].offset + + s_to_use = set() + s_to_fix = set() + + s_dependent = {} + + for l in symbol_pool.s: + if not type(symbol_pool.s[l].offset_g) in [int, long]+tab_int_size.keys(): + s_to_fix.add(l) + + if not l in symbol_pool.s or symbol_pool.s[l].offset_g == None: + raise ValueError("symbol missing?", l) + #construct dependant blocs tree + s_d = symbol_pool.s[l].offset_g[0] + if not s_d.name in s_dependent: + s_dependent[s_d.name] = set() + s_dependent[s_d.name].add(l) + else: + s_to_use.add(l) + + s_used = set() + total_fixed = 0 + + while s_to_use: + s = s_to_use.pop() + offset = symbol_pool.s[s].offset_g + + s_fixed = set() + if not s in s_dependent: + continue + for l in s_dependent[s]: + if symbol_pool.s[s].offset_g== None: + raise ValueError("unknown symbol: %s"%str(s)) + + symbol_pool.s[l].offset_g=offset+symbol_pool.s[l].offset_g[1].blen*symbol_pool.s[l].offset_g[2] + s_to_use.add(l) + total_fixed+=1 + s_fixed.add(l) + + for l in s_fixed: + s_to_fix.remove(l) + + +def asmbloc(mnemo, all_blocs): + #compute max bloc len + for b in all_blocs: + log_asmbloc.debug('---') + blen = 0 + blen_max = 0 + for instr in b.lines: + if isinstance(instr, asm_raw): + candidates = [instr.raw] + c = instr.raw + elif [True for a in instr.arg if mnemo.has_symb(a)]: + testing_arg = [mnemo.fix_symbol(a) for a in instr.arg] + sav_a = instr.arg + instr.arg = testing_arg + candidates=mnemo.asm(str(instr)) + if not candidates: + raise ValueError('cannot asm:%s'%str(instr)) + instr.arg = sav_a + + c = candidates[0] + blen_max+= len(candidates[-1])-len(candidates[0]) + else: + candidates=mnemo.asm(str(instr)) + if not candidates: + raise ValueError('cannot asm:%s'%str(instr)) + c = candidates[0] + log_asmbloc.debug(instr) + log_asmbloc.debug(candidates) + log_asmbloc.debug(repr(c)) + instr.data = c + blen +=len(c) + + b.blen = blen + #bloc with max rel values encoded + b.blen_max = blen+blen_max + log_asmbloc.info("blen: %d max: %d"%(b.blen, b.blen_max)) + + + +def asmbloc_final(mnemo, all_blocs, symbol_pool, symb_reloc_off = {}): + log_asmbloc.info("asmbloc_final") + fini =False + #asm with minimal instr len + #check if dst label are ok to this encoded form + #recompute if not + while not fini: + fini =True + my_symb_reloc_off = {} + + calc_symbol_offset(symbol_pool) + #test if bad encoded relative + for b,t in all_blocs: + offset_i = 0 + my_symb_reloc_off[b.label] = [] + for instr in b.lines: + if isinstance(instr, asm_raw): + offset_i+=len(instr.data) + continue + if not [True for a in instr.arg if mnemo.has_symb(a)]: + offset_i+=len(instr.data) + continue + + sav_a = instr.arg + + if instr.dstflow(): + lbls = {} + xxx = instr.getdstflow() + if len(xxx) !=1: + raise ValueError('multi dst ?!') + label = mnemo.get_label(xxx[0]) + is_mem = mnemo.is_mem(xxx[0]) + lbls[label.name] = label.offset_g + instr.fixdst(lbls, b.label.offset_g+b.blen, is_mem) + else: + instr.arg = [mnemo.fix_symbol(a, symbol_pool) for a in instr.arg] + symbol_reloc_off = [] + candidates=mnemo.asm(str(instr), symbol_reloc_off) + if not candidates: + raise ValueError('cannot asm:%s'%str(instr)) + c = candidates[0] + instr.arg = sav_a + + if len(c)>len(instr.data): + #good len, bad offset...XXX + b.blen = b.blen-len(instr.data)+len(c) + instr.data = c + fini=False + break + else: + l_dict = dict([[len(x),i] for i, x in enumerate(candidates)]) + instr.data = candidates[l_dict[len(instr.data)]] + + if l_dict[len(instr.data)] < len(symbol_reloc_off): + my_s = symbol_reloc_off[l_dict[len(instr.data)]] + else: + my_s = None + + if my_s!=None: + my_symb_reloc_off[b.label].append(offset_i+my_s) + + offset_i+=len(instr.data) + + for l in symbol_pool.s: + if symbol_pool.s[l].offset_g ==None: + fdfd + + #we have fixed all relative values + #recompute good offsets + for l in symbol_pool.s: + symbol_pool.s[l].offset = symbol_pool.s[l].offset_g + + for a, b in my_symb_reloc_off.items(): + symb_reloc_off[a] = b + +def asm_resolve_final(mnemo, all_bloc, symbol_pool, dont_erase = [], symb_reloc_off = {}, constrain_pos = False): + asmbloc(mnemo, all_bloc) + bloc_g = group_blocs(all_bloc) + if constrain_pos: + #XXX + print bloc_g + bloc_list = [(bcs[0].bloc_num, bcs[0].label) for bcs in bloc_g.values()] + bloc_list.sort() + bloc_list = [b[1] for b in bloc_list] + resolved_b = resolve_symbol_linear(bloc_list, bloc_g, dont_erase) + else: + resolved_b = resolve_symbol(bloc_g, dont_erase) + + asmbloc_final(mnemo, resolved_b, symbol_pool, symb_reloc_off) + + + written_bytes = {} + patches = {} + for b,t in resolved_b: + offset = b.label.offset + for i in b.lines: + patches[offset] = i.data + for c in range(len(i.data)): + if offset+c in written_bytes: + raise ValueError("overlapping bytes in asssembly %X"%int(offset)) + written_bytes[offset+c] = 1 + offset+=len(i.data) + + return resolved_b, patches + + +def patch_binary(f, resolved_b): + written_bytes = {} + for b,t in resolved_b: + offset = b.label.offset + f.seek(offset, 0) + for i in b.lines: + log_asmbloc.debug("%.8X %-30s %s"%(offset, repr(i.data), str(i))) + f.write(i.data) + for c in range(len(i.data)): + if offset+c in written_bytes: + log_asmbloc.error( "erase allready fixed bytes") + written_bytes[offset+c] = 1 + offset+=len(i.data) + return written_bytes + + +def blocs2str(b): + out = b.label.name+':\n' + for l in b.lines: + out+=str(l)+'\n' + return out + + +def find_parents(all_bloc, l): + p = set() + for b in all_bloc: + if l in [x.label for x in b.bto if isinstance(x.label, asm_label)]: + p.add(b.label) + return p + +def dead_bloc_rem(all_bloc, symbol_pool, keeped = []): + finish = False + while not finish: + finish = True + for b in all_bloc: + l = b.label + if l in keeped: + continue + p = find_parents(all_bloc, l) + if l in p: + p.remove(l) + if not len(p): + symbol_pool.remove(b.label) + all_bloc.remove(b) + finish = False + print 'del bloc %s'%str(l) + break + + + +def getbloc_around(all_bloc, a, level = 3, done = None, blocby_label = None): + + if not blocby_label: + blocby_label = {} + for b in all_bloc: + blocby_label[b.label] = b + + if done == None: + done = set() + + done.add(a) + + if not level: + return done + + for b in a.parents: + b = blocby_label[b] + if b in done: + continue + done.update(getbloc_around(all_bloc, b, level-1, done, blocby_label)) + for b in a.bto: + b = blocby_label[b.label] + if b in done: + continue + done.update(getbloc_around(all_bloc, b, level-1, done, blocby_label)) + return done + + +def getbloc_parents(all_bloc, a, level = 3, done = None, blocby_label = None): + + if not blocby_label: + blocby_label = {} + for b in all_bloc: + blocby_label[b.label] = b + + if done == None: + done = set() + + done.add(a) + + if not level: + return done + + for b in a.parents: + b = blocby_label[b] + if b in done: + continue + done.update(getbloc_parents(all_bloc, b, level-1, done, blocby_label)) + return done + +#get ONLY level_X parents +def getbloc_parents_strict(all_bloc, a, level = 3, rez = None, done = None, blocby_label = None): + + if not blocby_label: + blocby_label = {} + for b in all_bloc: + blocby_label[b.label] = b + if rez == None: + rez = set() + if done == None: + done = set() + + done.add(a) + if level == 0: + rez.add(a) + + if not level: + return rez + + for b in a.parents: + b = blocby_label[b] + if b in done: + continue + rez.update(getbloc_parents_strict(all_bloc, b, level-1, rez, done, blocby_label)) + return rez + + +def bloc_find_path(all_bloc, blocby_label, a, b, path = None, done = None): + if path == None: + path = [] + if done == None: + done = set() + + all_path = [] + for x in a.bto: + if not isinstance(x.label, asm_label) or not x.label in blocby_label: + continue + x = blocby_label[x.label] + + if x == b: + all_path += [path+[a]] + continue + + if x in done: + continue + + done.add(a) + all_path+=bloc_find_path(all_bloc, blocby_label, x, b, path+[a], done) + return all_path + + +def getblocby_offsetin(all_bloc, o): + for b in all_bloc: + for l in b.lines: + if o == l.offset: + return b + return None + +def getblocby_offsetinr(all_bloc, o): + for b in all_bloc: + min_ad = None + max_ad = None + for l in b.lines: + if min_ad == None or l.offset < min_ad: + min_ad = l.offset + if max_ad == None or l.offset > max_ad:#XXX + len l + max_ad = l.offset + if min_ad <= o <= max_ad: + return b + return None + + +def getlineby_offset(all_bloc, o): + for b in all_bloc: + for l in b.lines: + if l.offset == o: + return l + return None + +def getblocby_offset(all_bloc, o): + for b in all_bloc: + for l in b.lines: + if l.offset == o: + return b + return None + +def getblocby_label(all_bloc, l): + for b in all_bloc: + if b.label == l: + return b + return None + +def bloc_blink(all_bloc): + for b in all_bloc: + b.parents = find_parents(all_bloc, b.label) + + +def bloc_find_path_next(all_bloc, blocby_label, a, b, path = None): + if path == None: + path = [] + if a == b: + return [path] + + all_path = [] + for x in a.bto: + if x.c_t != asm_constraint.c_next: + continue + if not x.label in blocby_label: + print 'XXX unknown label' + continue + + x = blocby_label[x.label] + all_path+=bloc_find_path_next(all_bloc, blocby_label, x, b, path+[a]) + #stop if at least one path found + if all_path: + return all_path + + return all_path + + + +def bloc_merge(all_bloc, symbol_pool, dont_merge = []): + i = -1 + blocby_label = {} + for b in all_bloc: + blocby_label[b.label] = b + b.parents = find_parents(all_bloc, b.label) + + while i<len(all_bloc)-1: + i+=1 + b = all_bloc[i] + if b.label in dont_merge: + continue + p = set(b.parents) + #if bloc dont self ref + if b.label in p: + continue + #and bloc has only one parent + if len(p) !=1: + continue + #may merge + bpl = p.pop() + #bp = getblocby_label(all_bloc, bpl) + bp = blocby_label[bpl] + #and parent has only one son + if len(bp.bto)!=1: + continue + #and will not create next loop constraint + path = bloc_find_path_next(all_bloc, blocby_label, b, bp) + if path: + continue + if bp.lines: + l = bp.lines[-1] + #jmp opt; jcc opt + if l.is_subcall(): + continue + if l.breakflow() and l.dstflow(): + bp.lines.pop() + #merge + sons = b.bto[:] + + #update parents + for s in b.bto: + if not isinstance(s.label, asm_label): continue + if s.label.name == None: + continue + if not s.label in blocby_label: + print "unknown parent XXX" + continue + bs = blocby_label[s.label] + for p in list(bs.parents): + if p == b.label: + bs.parents.discard(p) + bs.parents.add(bp.label) + + bp.lines+=b.lines + bp.bto = b.bto + symbol_pool.remove(b.label) + del(all_bloc[i]) + i = -1 + + + +def extract_sub_graph_of_bloc(all_bloc, b_o): + blocby_label = {} + for b in all_bloc: + blocby_label[b.label] = b + b.parents = find_parents(all_bloc, b.label) + + out = [] + todo = set([b_o]) + done = set() + + while todo: + b = todo.pop() + if b in done: + continue + done.add(b) + out.append(b) + for c in b.bto: + if not isinstance(c.label, asm_label): + continue + bson = blocby_label[c.label] + todo.add(bson) + return out + + +def steal_bytes(in_str, arch_mn, ad, l): + in_str.setoffset(ad) + lines = [] + total_bytes = 0 + erased_asm = "" + callx86len = l + while total_bytes<callx86len: + lines.append(arch_mn.dis(in_str)) + total_bytes+=lines[-1].l + erased_asm+=str(lines[-1])+'\n' + return lines, total_bytes + + + + +def dis_multi_func(in_str, mn, symbol_pool, ad, dont_dis = [], follow_call = False, dontdis_retcall = False, amode="u32", sex=0, dis_bloc_callback =None ): + todo = ad[:] + done = set() + + + all_bloc = [] + job_done = set() + + call_ad = set(ad) + + while todo: + ad = todo.pop() + if ad in done: + continue + done.add(ad) + all_bloc__ = dis_bloc_all(mn, in_str, ad, job_done, symbol_pool, dont_dis, follow_call, False, dontdis_retcall, all_bloc = all_bloc, amode=amode, sex=sex, dis_bloc_callback = dis_bloc_callback ) + + for b in all_bloc: + if not b.lines: + #XXX not lines in bloc ??? + continue + l = b.lines[-1] + if not l.m.name.startswith('call'): continue + dst = mnemo.get_label(l.args[0]) + if not dst: continue + + todo.append(dst) + call_ad.add(dst) + + + #all_bloc_funcs[ad] = all_bloc + all_bloc = split_bloc(all_bloc, symbol_pool, more_ref = call_ad) + + return all_bloc + +def dis_one_bloc(in_str, mnemo, ad): + job_done = set() + symbol_pool = asm_symbol_pool() + all_bloc = dis_bloc_all(mnemo, in_str, ad, job_done, symbol_pool, bloc_wd = 1) + if len(all_bloc) != 1: + return None + return all_bloc[0] + + +def dis_bloc_simple(mnemo, in_str, ad, **kargs): + job_done = set() + symbol_pool = asm_symbol_pool() + if not "job_done" in kargs: + kargs["job_done"] = job_done + if not "symbol_pool" in kargs: + kargs["symbol_pool"] = symbol_pool + all_bloc = dis_bloc_all(mnemo, in_str, ad, **kargs) + return all_bloc + + +def dis_bloc_ia32(in_str, ad, **kargs): + from miasm.arch.ia32_arch import x86_mn + + job_done = set() + symbol_pool = asm_symbol_pool() + + if not "job_done" in kargs: + kargs["job_done"] = job_done + if not "symbol_pool" in kargs: + kargs["symbol_pool"] = symbol_pool + all_bloc = dis_bloc_all(x86_mn, in_str, ad, **kargs) + return all_bloc + +nx = None +try: + import networkx as nx +except: + pass + +if nx: + def is_isomorph(all_bloc1, all_bloc2): + + G1=nx.DiGraph() + G2=nx.DiGraph() + + for b in all_bloc1: + G1.add_node(b.label) + for t in b.bto: + G1.add_edge(b.label, t.label) + for b in all_bloc2: + G2.add_node(b.label) + for t in b.bto: + G2.add_edge(b.label, t.label) + + GM = nx.GraphMatcher(G1,G2) + is_isom = GM.is_isomorphic() + return GM.is_isomorphic(), GM.mapping + diff --git a/miasm/core/bin_stream.py b/miasm/core/bin_stream.py new file mode 100644 index 00000000..c8e64c8d --- /dev/null +++ b/miasm/core/bin_stream.py @@ -0,0 +1,101 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +class bin_stream_mother(type): + def __call__(self, *arg): + if arg and arg[0].__class__ in [str]: + cls = bin_stream_str + elif arg and type(arg[0]) is file: + cls = bin_stream_file + else: + cls = bin_stream_str + + i = cls.__new__(cls, cls.__name__, cls.__bases__, cls.__dict__) + i.__init__(*arg) + return i + + +class bin_stream(object): + __metaclass__ = bin_stream_mother + def __init__(self, *args, **kargs): + pass + def __repr__(self): + return "<%s !!>"%self.__class__.__name__ + + def hexdump(self, offset, l): + return + + + +class bin_stream_str(bin_stream): + def __init__(self, bin ="", offset = 0L): + if offset>len(bin): + raise IOError + self.bin = bin + self.offset = offset + self.l = len(bin) + if "is_addr_in" in self.bin.__class__.__dict__: + self.is_addr_in = lambda ad:self.bin.is_addr_in(ad) + + + def readbs(self, l=1): + if self.offset+l>self.l: + raise IOError + self.offset+=l + return self.bin[self.offset-l:self.offset] + + def writebs(self, l=1): + raise ValueError('writebs unsupported') + + def __str__(self): + out = self.bin[self.offset:] + return out + def setoffset(self, val): + val = val & 0xFFFFFFFF + self.offset = val + +class bin_stream_file(bin_stream): + def __init__(self, bin, offset=0L): + self.bin = bin + self.bin.seek(0, 2) + self.l = self.bin.tell() + self.offset = offset + + + + def getoffset(self): + return self.bin.tell() + + def setoffset(self, val): + val = val & 0xFFFFFFFF + self.bin.seek(val) + + offset = property(getoffset, setoffset) + + def readbs(self, l=1): + if self.offset+l>self.l: + raise IOError + return self.bin.read(l) + + def writebs(self, l=1): + if self.offset+l>self.l: + raise IOError + return self.bin.write(l) + + def __str__(self): + return str(self.bin) + diff --git a/miasm/core/memory_pool.py b/miasm/core/memory_pool.py new file mode 100644 index 00000000..a0ddaf1b --- /dev/null +++ b/miasm/core/memory_pool.py @@ -0,0 +1,283 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +import array +import struct +import cPickle +import StringIO +from numpy import uint32 + +from elfesteem import * + + +class mempool: + def gen_pad(x): + if x>0: + return '\x00'*x + else: + return '' + def __init__(self, start, stop, perm = "RW", data = {}, name = "", extern_func = {}): + self.start = start + self.stop = stop + self.extern_func = extern_func + self.perm_R = "R" in perm + self.perm_W = "W" in perm + self.perm_X = "X" in perm + self.name = name + + my_data = array.array('B') + + if type(data) is dict: + pad = stop-start + pass + + elif type(data) is file: + pos = data.tell() + data.seek(0, 2) + end = data.tell() + data.seek(pos) + pad = stop-start - (end-pos) + if pad>0: + my_data = my_data.fromfile(data, end-pos) + else: + my_data = my_data.fromfile(f, stop-start) + else: + pad = stop-start - len(data) + my_data.fromstring(str(data)) + + + my_data.extend([0 for x in xrange(pad)]) + self.data = my_data + + def __str__(self): + return repr(self)+'<%.8X-%.8X>'%(int(self.start),int(self.stop))+"-R"[self.perm_R]+"-W"[self.perm_W]+"-X"[self.perm_X]+" "+self.name + + def has_extern(self, address): + if address in self.extern_func: + return self.extern_func[address] + return False + + def get_b(self, x): + return self.data[int(uint32(x))-self.start] + def get_w(self, x): + return struct.unpack('H', self.data[int(uint32(x))-self.start:int(uint32(x))-self.start+2].tostring())[0] + def get_d(self, x): + return struct.unpack('L', self.data[int(uint32(x))-self.start:int(uint32(x))-self.start+4].tostring())[0] + def get_data(self, x, l): + return self.data[int(uint32(x))-self.start:int(uint32(x))-self.start+l] + + def set_b(self, x, v): + self.data[int(uint32(x))-self.start] = int(v) + def set_w(self, x, v): + i = map(ord, struct.pack('H', int(v))) + i.reverse() + for j in xrange(2): + self.data[int(uint32(x))-self.start+j] = i.pop() + def set_d(self, x, v): + i = map(ord, struct.pack('L', int(v))) + i.reverse() + for j in xrange(4): + self.data[int(uint32(x))-self.start+j] = i.pop() + def set_data(self, x, v): + for i, c in enumerate(v): + self.data[int(uint32(x))-self.start+i] = ord(c) + + def to_file(self, f): + if type(f) is str: + f = open(f,"w") + my_data = self.data + self.data = self.data.tostring() + cPickle.dump(self, f) + self.data = my_data + + @staticmethod + + def from_file(f): + if type(f) is str: + f = open(f,"r") + m = cPickle.load(f) + my_data = array.array('B') + my_data.fromstring(m.data) + m.data = my_data + return m + +class mempool_manager: + def __init__(self, mems = []): + self._mems = mems + + def __str__(self): + out = repr(self)+'\n' + out += reduce(lambda x,y:x+str(y)+'\n', self._mems, "") + return out[:-1] + + def get_mems(self): + return self._mems + + def set_mems(self): + tmp = [[m.start, m.stop] for m in self._mems] + for m in tmp: + if m[0]>m[1]: + raise 'stop inf start: %s'%str(m) + for i, m in enumerate(tmp[:-1]): + if m[1] > tmp[i+1][0]: + raise 'overlapping mems: %s %s'%(str(m), str(tmp[i+1])) + + return self._mems + + mems = property(get_mems, set_mems) + + def get_mem_pool(self, x): + x = int(uint32(x)) + for m in self._mems: + if x >=m.start and x <m.stop: + return m + raise 'unknown mem', str(x) + + + def get_b(self, x): + m = self.get_mem_pool(x) + return m.get_b(x) + + def get_w(self, x): + m = self.get_mem_pool(x) + try: + return m.get_w(x) + except: + pass + out = "" + for i in xrange(2): + m = self.get_mem_pool(x+i) + out+=chr(m.get_b(x+i)) + return struct.unpack('H', out)[0] + + def get_d(self, x): + m = self.get_mem_pool(x) + try: + return m.get_d(x) + except: + pass + out = "" + for i in xrange(4): + m = self.get_mem_pool(x+i) + out+=chr(m.get_b(x+i)) + return struct.unpack('L', out)[0] + + def get_data(self, x, l): + m = self.get_mem_pool(x) + try: + return m.get_data(x,l) + except: + pass + out = "" + for i in xrange(l): + m = self.get_mem_pool(x+i) + out+=chr(m.get_b(x+i)) + return out + + def set_b(self, x, v): + m = self.get_mem_pool(x) + m.set_b(x,v) + + def set_w(self, x, v): + m = self.get_mem_pool(x) + try: + m.set_w(x, v) + return + except: + pass + i = map(ord, struct.pack('H', int(v))) + i.reverse() + for j in xrange(2): + m = self.get_mem_pool(x+j) + m.set_b(x+j, i.pop()) + + def set_d(self, x, v): + m = self.get_mem_pool(x) + try: + m.set_d(x, v) + return + except: + pass + i = map(ord, struct.pack('L', int(v))) + i.reverse() + print hex(int(x)), i + for j in xrange(4): + m = self.get_mem_pool(x+j) + print j, m + m.set_b(x+j, i.pop()) + print 'iii' + + def set_data(self, x, v): + m = self.get_mem_pool(x) + try: + m.set_data(x, v) + return + except: + pass + for i, c in enumerate(v): + m = self.get_mem_pool(x+i) + m.set_b(x+i, ord(c)) + + + def to_file(self, f): + if type(f) is str: + f = open(f,"w") + for m in self._mems: + m.to_file(f) + + @staticmethod + + def from_file(f): + if type(f) is str: + f = open(f,"r") + mems = [] + while True: + try: + mems.append(mempool.from_file(f)) + except: + break + return mempool_manager(mems) + + +def load_pe(e, loadhdr=False): + mems = [] + if loadhdr: + hdr = open(fname, 'rb').read(0x1000) + mems.append(mempool(e.NThdr.ImageBase, + e.NThdr.ImageBase+0x1000, + 'RWX', hdr, "PE HDR")) + for section in e.SHList: + section_size = max(section.rawsize,section.size) + section_size = (section_size+0xfff)&~0xfff + mems.append(mempool(e.NThdr.ImageBase+section.addr, + e.NThdr.ImageBase+section.addr+section_size, + 'RWX', section.data, section.name.replace('\x00', ' '))) + + return mems + + +def load_from_pe(pe): + + mems = [] + for section in pe.SHList: + section_size = max(section.rawsize,section.size) + section_size = (section_size+0xfff)&~0xfff + mems.append(mempool(pe.NThdr.ImageBase+section.addr, + pe.NThdr.ImageBase+section.addr+section_size, + 'RWX', section.data, section.name.replace('\x00', ' '))) + + return mems diff --git a/miasm/core/parse_ad.py b/miasm/core/parse_ad.py new file mode 100644 index 00000000..be2e5a38 --- /dev/null +++ b/miasm/core/parse_ad.py @@ -0,0 +1,343 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from miasm.arch.ia32_reg import x86_afs +from numpy import int32, uint32 + +def dict_add(a, b): + tmp = dict(a) + for k in b: + #special case + if k == x86_afs.symb: + if k in tmp: + tmp[k] = dict_add(tmp[k], b[k]) + else: + tmp[k] = dict(b[k]) + continue + #normal case + if k in tmp: + tmp[k]+=b[k] + else: + tmp[k] = b[k] + if tmp[k]==0: + del(tmp[k]) + return tmp + +def dict_sub(a, b): + tmp = dict(a) + for k in b: + #special case + if k == x86_afs.symb: + if k in tmp: + tmp[k] = dict_sub(tmp[k], b[k]) + else: + tmp[k] = dict({},b[k]) + continue + #normal case + if k in tmp: + tmp[k]-=b[k] + else: + tmp[k] = -b[k] + if tmp[k]==0: + del(tmp[k]) + return tmp + +def dict_mul(a, b): + if a.keys() == [x86_afs.imm]: + ret = {} + for k in b: + if k == x86_afs.symb: + ret[k] = dict_mul({x86_afs.imm:a[x86_afs.imm]}, b[k]) + else: + ret[k] = a[x86_afs.imm]*b[k] + return ret + if b.keys() == [x86_afs.imm]: + ret = {} + for k in a: + if k == x86_afs.symb: + ret[k] = dict_mul({x86_afs.imm:b[x86_afs.imm]}, a[k]) + else: + ret[k] = b[x86_afs.imm]*a[k] + return ret + + raise 'bad dict mul %s'%(str(a)+str(b)) + +keywords = ("BYTE", "WORD", "DWORD", "SINGLE", "DOUBLE", + "ES", "CS", "SS", "DS", "FS", "GS", + "PTR") + + +tokens = keywords +( + 'NUMBER', + 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', + 'LPAREN','RPAREN','LBRA','RBRA', 'COLON', + 'OFFSET','NAME', + ) + +# Tokens + +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_EQUALS = r'=' +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_LBRA = r'\[' +t_RBRA = r'\]' +t_COLON = r':' +t_OFFSET = r'OFFSET' + +def t_NAME(t): + r'[a-zA-Z_][a-zA-Z0-9_]*' + if t.value.upper() in keywords: + t.type = t.value.upper() + t.value = t.value.lower() + return t + + + +def t_NUMBER(t): + r'((((0x)|(0X))[0-9a-fA-F]+)|(\d+))' + try: + if t.value.startswith("0x") or t.value.startswith("0X"): + t.value = int(t.value, 16) + else: + t.value = int(t.value) + except ValueError: + print("Integer value too large %d", t.value) + t.value = 0 + return t + +# Ignored characters +t_ignore = " \t" + +def t_newline(t): + r'\n+' + t.lexer.lineno += t.value.count("\n") + +def t_error(t): + print("Illegal character '%s'" % t.value[0]) + t.lexer.skip(1) + + +# Build the lexer +import ply.lex as lex +lex.lex() + + +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +def p_expression_1(t): + '''expression : ''' + return {} +def p_expression_2(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + + if t[2] == '+': + t[0] = dict_add(t[1], t[3]) + elif t[2] == '-': + t[0] = dict_sub(t[1], t[3]) + elif t[2] == '*': + t[0] = dict_mul(t[1], t[3]) + elif t[2] == '/': + raise 'bad op' + else: + raise 'bad op' + + +def p_expression_3(t): + '''expression : LPAREN expression RPAREN''' + t[0] = t[2] + +def p_expression_4(t): + '''expression : OFFSET expression ''' + t[0] = t[2] + +def p_expression_5(t): + '''expression : MINUS expression %prec UMINUS''' + t[0] = dict([[k,-t[2][k]] for k in t[2]]) + +def p_expression_6(t): + '''expression : NUMBER''' + t[0] = {x86_afs.imm:int(int32(uint32(int(t[1]))))} + + +#"[@?_a-zA-Z\.$][?\.a-zA-Z0-9_@$]*" +def p_expression_8(t): + '''expression : NAME''' + if t[1] in x86_afs.reg_list32: + size = x86_afs.u32 + elif t[1] in x86_afs.reg_list16: + size = x86_afs.u16 + elif t[1] in x86_afs.reg_list8: + size = x86_afs.u08 + elif t[1] in x86_afs.reg_flt: + size = x86_afs.f32 + elif t[1] in x86_afs.reg_dr: + size = x86_afs.u32 + elif t[1] in x86_afs.reg_cr: + size = x86_afs.u32 + elif t[1] in x86_afs.reg_sg: + size = x86_afs.u32 + + + else: + #raise 'bad reg size' + t[0] = {x86_afs.symb:{t[1]:1}} + return + t[0] ={x86_afs.reg_dict[t[1]]:1, x86_afs.size : size} + +def p_PTRSIZE(t): + '''PTRSIZE : BYTE + | WORD + | DWORD + | SINGLE + | DOUBLE + ''' + t[0] = t[1] + +def p_PTRMEM(t): + '''PTRMEM : PTR''' + t[0] = t[1] + + + + + + + +def p_OPTSEG(t): + '''OPTSEG : ES + | CS + | SS + | DS + | FS + | GS + ''' + t[0] = t[1] + +def p_opt_seg_1(t): + '''opt_seg : OPTSEG COLON ''' + t[0] = {x86_afs.segm:x86_afs.reg_sg.index(t[1])} + +def p_expression_9(t): + '''expression : PTRSIZE PTRMEM LBRA expression RBRA + | PTRSIZE PTRMEM opt_seg LBRA expression RBRA ''' + size = t[1] + if len(t) == 6: + index = 4 + else: + index = 5 + if size=='byte': + t[index][x86_afs.ad] = x86_afs.u08 + elif size == 'word': + t[index][x86_afs.ad] = x86_afs.u16 + elif size == 'dword': + t[index][x86_afs.ad] = x86_afs.u32 + elif size == 'single': + t[index][x86_afs.ad] = x86_afs.f32 + elif size == 'double': + t[index][x86_afs.ad] = x86_afs.f64 + else: + raise 'bad address size' + if len(t) !=6: + t[index].update(t[3]) + t[0] = t[index] + +def p_expression_10(t): + '''expression : LBRA expression RBRA + | opt_seg LBRA expression RBRA ''' + if len(t) == 4: + t[2][x86_afs.ad] = x86_afs.u32 + t[0] = t[2] + else: + t[3][x86_afs.ad] = x86_afs.u32 + t[3].update(t[1]) + t[0] = t[3] + +def parse_ad(a): + tmp_dict = {} + l = yacc.parse(a) + + if not x86_afs.ad in l: + l[x86_afs.ad] = False + else: + l[x86_afs.size] = l[x86_afs.ad] + + if not x86_afs.size in l: + l[x86_afs.size] = x86_afs.u32 + + + + return l + +import ply.yacc as yacc +yacc.yacc() + +def ad_to_generic(a): + + #opt imm + out = [] + to_add = [] + #generic ad size + if a[x86_afs.ad]: + a[x86_afs.ad] = True + + + #imm can always be encoded in u32 + to_add.append({x86_afs.imm:x86_afs.u32}) + + if x86_afs.imm in a: + if a[x86_afs.imm] >=0 and a[x86_afs.imm] <=0xFF: + to_add.append({x86_afs.imm:x86_afs.u08}) + if a[x86_afs.imm] >=-128 and a[x86_afs.imm] <128: + to_add.append({x86_afs.imm:x86_afs.s08}) + else: + to_add.append({x86_afs.imm:x86_afs.u08}) + to_add.append({x86_afs.imm:x86_afs.s08}) + + + if not x86_afs.imm in a: + out.append(a) + else: + i = a[x86_afs.imm] + if i<128 and i >= -128: + to_add.append({x86_afs.imm:x86_afs.s08}) + if i<=0xFF and i >=0 : + to_add.append({x86_afs.imm:x86_afs.u08}) + + for kv in to_add: + tmp = dict(a) + tmp.update(kv) + out.append(tmp) + + out_unik = [] + for o in out: + if not o in out_unik: + out_unik.append(o) + + return out_unik + + diff --git a/miasm/core/parse_asm.py b/miasm/core/parse_asm.py new file mode 100644 index 00000000..64618626 --- /dev/null +++ b/miasm/core/parse_asm.py @@ -0,0 +1,232 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from miasm.core.asmbloc import * +from shlex import shlex + + +declarator = {'byte':'B', 'long':'I'} +def guess_next_new_label(symbol_pool, gen_label_index = 0): + i = 0 + while True: + l = asm_label(i) + i+=1 + if not l.name in symbol_pool.s: + return l + + +def parse_txt(mnemo, txt, symbol_pool = None, gen_label_index = 0): + if symbol_pool == None: + symbol_pool = asm_symbol_pool() + + lines_text = [] + lines_data = [] + lines_bss = [] + + lines=lines_text + #parse each line + for line in txt.split('\n'): + #empty + if re.match(r'\s*$', line): + continue + #comment + if re.match(r'\s*;\S*', line): + continue + #directive + if re.match(r'\s*\.', line): + r = re.match(r'\s*\.(\S+)', line) + directive = r.groups()[0] + if directive == 'text': + lines = lines_text + continue + if directive == 'data': + lines = lines_data + continue + if directive == 'bss': + lines = lines_bss + continue + if directive in ['string', 'ascii']: + #XXX HACK + line = line.replace(r'\n', '\n').replace(r'\r', '\r') + raw = line[line.find(r'"')+1:line.rfind(r"'")] + if directive == 'string': + raw+="\x00" + lines.append(asm_raw(raw)) + continue + if directive == 'ustring': + #XXX HACK + line = line.replace(r'\n', '\n').replace(r'\r', '\r') + raw = line[line.find(r'"')+1:line.rfind(r"'")]+"\x00" + raw = "".join(map(lambda x:x+'\x00', raw)) + lines.append(asm_raw(raw)) + continue + if directive in declarator: + data_raw = [x for x in shlex(line[r.end():]) if not x in ','] + data_int = [] + for b in data_raw: + if re.search(r'0x', b): + data_int.append(int(b, 16)) + else: + data_int.append(int(b)) + raw = reduce(lambda x,y:x+struct.pack(declarator[directive], y), data_int, "") + lines.append(asm_raw(raw)) + continue + if directive == 'split': #custom command + lines.append(asm_raw(line.strip())) + continue + + raise "unknown directive %s"%str(directive) + + #label + r = re.match(r'\s*(\S+)\s*:', line) + if r: + l = r.groups()[0] + l = symbol_pool.getby_name_create(l) + lines.append(l) + continue + + #code + if ';' in line: + line = line[:line.find(';')] + prefix, name, args = mnemo.parse_mnemo(line) + #print prefix, name, args + args = [mnemo.parse_address(a) for a in args] + #pool symbols + for a in args: + + if mnemo.has_symb(a): + symbs = mnemo.get_symbols(a) + symbs_dct = {} + for s, count in symbs: + if isinstance(s, asm_label): + continue + l = symbol_pool.getby_name_create(s) + symbs_dct[s] = l + mnemo.names2symbols(a, symbs_dct) + + + + + if mnemo.rebuilt_inst: + candidates=dict([[len(x),x] for x in mnemo.asm(line)]) + if not candidates: + raise ValueError('cannot asm %s'%str(line)) + c = candidates[min(candidates.keys())] + c+=mnemo.prefix2hex(prefix) + instr = mnemo.dis(c) + else: + instr = mnemo.asm_instr(line) + instr.arg = args + lines.append(instr) + + log_asmbloc.info( "___pre asm oki___") + #make blocs + #gen_label_index = 0 + + + + all_blocs_sections = [] + bloc_num = 0 + for lines in [lines_text, lines_data, lines_bss]: + state = 0 + i = 0 + all_blocs = [] + all_blocs_sections.append(all_blocs) + + bloc_to_nlink = None + block_may_link = False + while i <len(lines): + #no current bloc + if state == 0: + if not isinstance(lines[i], asm_label): + l = guess_next_new_label(symbol_pool) + symbol_pool.add(l) + lines[i:i] = [l] + else: + l = lines[i] + b = asm_bloc(l) + b.bloc_num = bloc_num + bloc_num+=1 + all_blocs.append(b) + state = 1 + i+=1 + if bloc_to_nlink: + bloc_to_nlink.addto(asm_constraint(b.label, asm_constraint.c_next)) + bloc_to_nlink = None + + #in bloc + elif state == 1: + #asm_raw + if isinstance(lines[i], asm_raw): + if lines[i].raw.startswith('.split'): + state = 0 + block_may_link = False + i+=1 + else: + b.addline(lines[i]) + i+=1 + #asm_label + elif isinstance(lines[i], asm_label): + if block_may_link: + b.addto(asm_constraint(lines[i], asm_constraint.c_next)) + block_may_link = False + state = 0 + #instruction + else: + b.addline(lines[i]) + if lines[i].dstflow(): + mydst = lines[i].arg + + if len(mydst)==1 and mnemo.get_symbols(mydst[0]): + arg = dict(mydst[0]) + symbs = mnemo.get_symbols(arg) + """ + TODO XXX redo this (as many miasm parts) + """ + l = symbs[0][0] + lines[i].setdstflow([l]) + b.addto(asm_constraint(l, asm_constraint.c_to)) + + # TODO XXX redo this really + + if not lines[i].breakflow() and i+1 < len(lines): + if isinstance(lines[i+1], asm_label): + l = lines[i+1] + else: + l = guess_next_new_label(symbol_pool) + symbol_pool.add(l) + lines[i+1:i+1] = [l] + else: + state = 0 + + if lines[i].splitflow(): + bloc_to_nlink = b + if not lines[i].breakflow() or lines[i].splitflow(): + block_may_link = True + else: + block_may_link = False + + + i+=1 + + + + + for b in all_blocs_sections[0]: + log_asmbloc.info( b) + + return all_blocs_sections, symbol_pool diff --git a/miasm/expression/__init__.py b/miasm/expression/__init__.py new file mode 100644 index 00000000..fbabaacf --- /dev/null +++ b/miasm/expression/__init__.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# diff --git a/miasm/expression/expression.py b/miasm/expression/expression.py new file mode 100644 index 00000000..4e4563c7 --- /dev/null +++ b/miasm/expression/expression.py @@ -0,0 +1,754 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from numpy import uint8, uint16, uint32, uint64, int8, int16, int32, int64 +tip = 'tip' + + +float_stack = 'float_stack' +float_stack_ptr = 'float_stack_ptr' + +def slice_rest(size, start, stop): + if start >=size or stop > size: raise 'bad slice rest %s %s %s'%(str(size), str(start), str(stop)) + if start == stop: return [(0,size)] + rest = [] + if start !=0: + rest.append((0, start)) + if stop < size: + rest.append((stop, size)) + + return rest + +tab_int_size = {int8:8, + uint8:8, + int16:16, + uint16:16, + int32:32, + uint32:32, + int64:64, + uint64:64 + } + +my_size_mask = {1:1, 8:0xFF, 16:0xFFFF, 32:0xFFFFFFFF, 64:0xFFFFFFFFFFFFFFFFL} + + + +def get_missing_interval(all_intervals, i_min = 0, i_max = 32): + my_intervals = all_intervals[:] + my_intervals.sort() + my_intervals.append((i_max, i_max)) + + missing_i = [] + last_pos = i_min + for start, stop in my_intervals: + if last_pos != start: + missing_i.append((last_pos, start)) + last_pos = stop + + return missing_i + + +class Expr: + is_term = False + is_simp = False + is_eval = False + def __init__(self, arg): + self.arg = arg + def __str__(self): + return str(self.arg) + def __getitem__(self, i): + if not isinstance(i, slice): + print i + raise "bad slice" + start, stop, step = i.indices(0x1337BEEF) + return ExprSlice(self, start, stop) + def get_r(self, mem_read=False): + return self.arg.get_r(mem_read) + def get_w(self): + return self.arg.get_w() + def get_size(self): + return arg.get_size() + def __repr__(self): + return "<%s 0x%x>"%(self.__class__.__name__, id(self)) + def __ne__(self, a): + return not self.__eq__(a) + + def toC(self): + print self + fdsfs + return self.arg.toC() + + def __add__(self, a): + return ExprOp('+', self, a) + def __sub__(self, a): + return ExprOp('-', self, a) + def __div__(self, a): + return ExprOp('/', self, a) + def __mul__(self, a): + return ExprOp('*', self, a) + def __lshift__(self, a): + return ExprOp('<<', self, a) + def __rshift__(self, a): + return ExprOp('>>', self, a) + def __xor__(self, a): + return ExprOp('^', self, a) + def __or__(self, a): + return ExprOp('|', self, a) + def __and__(self, a): + return ExprOp('&', self, a) + +class ExprTop(Expr): + def __init__(self, e=None): + self.e = e + pass + def __str__(self): + return "top(%s)"%str(self.e) + def get_r(self, mem_read=False): + raise ValueError("get_r on TOP") + def get_w(self): + raise ValueError("get_r on TOP") + def get_size(self): + raise ValueError("get_size on TOP") + def reload_expr(self, g = {}): + return ExprTop(self.e) + def __eq__(self, a): + return isinstance(a, ExprTop) + def __hash__(self): + return 0x1337beef + + def toC(self): + raise ValueError('cannot toC TOP') + + +class ExprInt(Expr): + def __init__(self, arg): + if not type(arg) in tab_int_size: + raise 'arg must by numpy int! %s'%str(arg) + self.arg = arg + def __str__(self): + if self.arg < 0: + return str("-0x%X"%-int(self.arg&0xffffffffffffffffL)) + else: + return str("0x%X"%int(self.arg&0xffffffffffffffffL)) + def get_r(self, mem_read=False): + return set() + def get_w(self): + return set() + def get_size(self): + return 8*self.arg.nbytes + def reload_expr(self, g = {}): + return ExprInt(self.arg) + def __contains__(self, e): + return self == e + def replace_expr(self, g = {}): + if self in g: + return g[self] + return self + def __eq__(self, a): + if not isinstance(a, ExprInt): + return False + return self.arg == a.arg + def __hash__(self): + return hash(self.arg) + def __repr__(self): + return Expr.__repr__(self)[:-1]+" 0x%X>"%int(self.arg&0xffffffffffffffffL) + + def toC(self): + return str(self) + + +class ExprId(Expr): + def __init__(self, name, size = 32, is_term = False): + self.name, self.size = name, size + self.is_term = is_term + def __str__(self): + return str(self.name) + def get_r(self, mem_read=False): + return set([self]) + def get_w(self): + return set([self]) + def get_size(self): + return self.size + def reload_expr(self, g = {}): + if self in g: + return g[self] + else: + return ExprId(self.name, self.size) + if self in g: + return g[self] + return self + def __contains__(self, e): + return self == e + def replace_expr(self, g = {}): + if self in g: + return g[self] + return self + def __eq__(self, a): + if not isinstance(a, ExprId): + return False + if self.name == a.name and self.size != a.size: + fdsfdsfdsdsf + return self.name == a.name and self.size == a.size + def __hash__(self): + return hash(self.name) + def __repr__(self): + return Expr.__repr__(self)[:-1]+" %s>"%self.name + + def toC(self): + return str(self) + +memreg = ExprId('MEM') + + + +class ExprAff(Expr): + def __init__(self, dst, src): + + #if dst is slice=> replace with id make composed src + if isinstance(dst, ExprSlice): + self.dst = dst.arg + rest = [ExprSliceTo(ExprSlice(dst.arg, *r), *r) for r in slice_rest(dst.arg.size, dst.start, dst.stop)] + all_a = [(dst.start, ExprSliceTo(src, dst.start, dst.stop))]+ [(x.start, x) for x in rest] + all_a.sort() + self.src = ExprCompose([x[1] for x in all_a]) + else: + self.dst, self.src = dst,src + + def __str__(self): + return "%s = %s"%(str(self.dst), str(self.src)) + def get_r(self, mem_read=False): + return self.src.get_r(mem_read) + def get_w(self): + if isinstance(self.dst, ExprMem): + return set([self.dst]) #[memreg] + else: + return self.dst.get_w() + #return dst size? XXX + def get_size(self): + return self.dst.get_size() + def reload_expr(self, g = {}): + if self in g: + return g[self] + dst = self.dst + if isinstance(dst, Expr): + dst = self.dst.reload_expr(g) + src = self.src + if isinstance(src, Expr): + src = self.src.reload_expr(g) + + return ExprAff(dst, src ) + def __contains__(self, e): + return self == e or self.src.__contains__(e) or self.dst.__contains__(e) + def replace_expr(self, g = {}): + if self in g: + return g[self] + dst = self.dst.replace_expr(g) + src = self.src.replace_expr(g) + return ExprAff(dst, src) + + def __eq__(self, a): + if not isinstance(a, ExprAff): + return False + return self.src == a.src and self.dst == a.dst + def __hash__(self): + return hash(self.dst)^hash(self.src) + + def toC(self): + return "%s = %s"%(self.dst.toC(), self.src.toC()) + + + #XXX /!\ for hackish expraff to slice + def get_modified_slice(self): + dst = self.dst + if not isinstance(self.src, ExprCompose): + raise ValueError("get mod slice not on expraff slice", str(self)) + modified_s = [] + for x in self.src.args: + if x.arg.arg != dst or x.start != x.arg.start or x.stop != x.arg.stop: + modified_s.append(x) + + return modified_s + + +class ExprCond(Expr): + def __init__(self, cond, src1, src2): + self.cond, self.src1, self.src2 = cond, src1, src2 + def __str__(self): + return "%s?(%s,%s)"%(str(self.cond), str(self.src1), str(self.src2)) + def get_r(self, mem_read=False): + out=self.cond.get_r(mem_read).union(self.src1.get_r(mem_read)).union(self.src2.get_r(mem_read)) + return out + def get_w(self): + return set() + #return src1 size? XXX + def get_size(self): + return self.src1.get_size() + def reload_expr(self, g = {}): + src1 = self.src1 + if isinstance(src1, Expr): + src1 = self.src1.reload_expr(g) + src2 = self.src2 + if isinstance(src2, Expr): + src2 = self.src2.reload_expr(g) + cond = self.cond + if isinstance(cond, Expr): + cond = self.cond.reload_expr(g) + return ExprCond(cond, src1, src2 ) + def replace_expr(self, g = {}): + if self in g: + return g[self] + cond = self.cond.replace_expr(g) + src1 = self.src1.replace_expr(g) + src2 = self.src2.replace_expr(g) + return ExprCond(cond, src1, src2 ) + def __contains__(self, e): + return self == e or self.cond.__contains__(e) or self.src1.__contains__(e) or self.src2.__contains__(e) + + + def __eq__(self, a): + if not isinstance(a, ExprCond): + return False + return self.cond == a.cond and self.src1 == a.src1 and self.src2 == a.src2 + def __hash__(self): + return hash(self.cond)^hash(self.src1)^hash(self.src2) + + def toC(self): + return "(%s?%s:%s)"%(self.cond.toC(), self.src1.toC(), self.src2.toC()) + + +class ExprMem(Expr): + def __init__(self, arg, size = 32): + if not isinstance(arg, Expr): raise 'arg must be expr' + self.arg, self.size = arg, size + def __str__(self): + return "@%d[%s]"%(self.size, str(self.arg)) + def get_r(self, mem_read=False): + if mem_read: + return set(self.arg.get_r(mem_read).union(set([self]))) + else: + return set([self]) + def get_w(self): + return set([self]) #[memreg] + def get_size(self): + return self.size + def reload_expr(self, g = {}): + arg = self.arg + if isinstance(arg, Expr): + arg = self.arg.reload_expr(g) + + + return ExprMem(arg, self.size ) + def __contains__(self, e): + return self == e or self.arg.__contains__(e) + + def replace_expr(self, g = {}): + if self in g: + return g[self] + arg = self.arg.replace_expr(g) + return ExprMem(arg, self.size ) + + def __eq__(self, a): + if not isinstance(a, ExprMem): + return False + return self.arg == a.arg and self.size == a.size + def __hash__(self): + return hash(self.arg)^hash(self.size) + + def toC(self): + return "MEM_LOOKUP_%.2d(%s)"%(self.size, self.arg.toC()) + + +class ExprOp(Expr): + def __init__(self, op, *args): + self.op, self.args = op, args + def __str__(self): + if len(self.args) == 2: + return '('+str(self.args[0]) + ' ' + self.op + ' ' + str(self.args[1]) + ')' + elif len(self.args)> 2: + return self.op + '(' + ', '.join([str(x) for x in self.args]) + ')' + else: + return reduce(lambda x,y:x+' '+str(y), self.args, '('+str(self.op))+')' + def get_r(self, mem_read=False): + return reduce(lambda x,y:x.union(y.get_r(mem_read)), self.args, set()) + def get_w(self): + raise ValueError('op cannot be written!', self) + #return 1st arg size XXX + def get_size(self): + a = self.args[0].get_size() + if len(self.args)>1: + if not a: + a = self.args[1].get_size() + return a + def reload_expr(self, g = {}): + args = [] + for a in self.args: + if isinstance(a, Expr): + args.append(a.reload_expr(g)) + else: + args.append(a) + + return ExprOp(self.op, *args ) + def __contains__(self, e): + if self == e: + return True + for a in self.args: + if a.__contains__(e): + return True + return False + def replace_expr(self, g = {}): + if self in g: + return g[self] + args = [] + for a in self.args: + args.append(a.replace_expr(g)) + return ExprOp(self.op, *args ) + + def __eq__(self, a): + if not isinstance(a, ExprOp): + return False + if self.op !=a.op: + return False + if len(self.args) != len(a.args): + return False + for i, x in enumerate(self.args): + if not x == a.args[i]: + return False + return True + def __hash__(self): + h = hash(self.op) + for a in self.args: + h^=hash(a) + return h + + def toC(self): + dct_shift= {'a>>':"right_arith", + '>>':"right_logic", + '<<':"left_logic", + 'a<<':"left_logic"} + dct_rot = {'<<<':'rot_left', + '>>>':'rot_right'} + if len(self.args)==1: + if self.op == 'parity': + return "parity(%s&0x%x)"%(self.args[0].toC(), my_size_mask[self.args[0].get_size()]) + elif self.op == '!': + return "(~ %s)&0x%x"%(self.args[0].toC(), my_size_mask[self.args[0].get_size()]) + elif self.op in ['int_32_to_double', 'int_64_to_double']: + return "%s(%s)"%(self.op, self.args[0].toC()) + elif self.op == 'double_to_int_32': + return "%s(%s)"%(self.op, self.args[0].toC()) + elif self.op in ['mem_32_to_double', 'mem_64_to_double']: + return "%s(%s)"%(self.op, self.args[0].toC()) + elif self.op.startswith("double_to_mem_"): + return "%s(%s)"%(self.op, self.args[0].toC()) + else: + fsdfdsf + return '('+str(self.op)+self.args[0].toC()+')' + elif len(self.args)==2: + if self.op == "==": + return '(((%s&0x%x) == (%s&0x%x))?1:0)'%(self.args[0].toC(), my_size_mask[self.args[0].get_size()], self.args[1].toC(), my_size_mask[self.args[1].get_size()]) + elif self.op in dct_shift: + return 'shift_%s_%.2d(%s , %s)'%(dct_shift[self.op], + self.args[0].get_size(), + self.args[0].toC(), + self.args[1].toC()) + elif self.op in ['+', '-', '*', '^', '&', '|']: + return '(((%s&0x%x) %s (%s&0x%x))&0x%x)'%(self.args[0].toC(), + my_size_mask[self.args[0].get_size()], + str(self.op), + self.args[1].toC(), + my_size_mask[self.args[1].get_size()], + my_size_mask[self.args[0].get_size()]) + elif self.op in dct_rot: + return '(%s(%s, %s, %s) &0x%x)'%(dct_rot[self.op], + self.args[0].get_size(), + self.args[0].toC(), + self.args[1].toC(), + my_size_mask[self.args[0].get_size()]) + + elif self.op == '*lo': + return 'mul_lo_op(%s, %s, %s)' %( + self.args[0].get_size(), + self.args[0].toC(), + self.args[1].toC()) + + elif self.op == 'umul32_lo': + return 'mul_lo_op(%s, %s, %s)' %( + self.args[0].get_size(), + self.args[0].toC(), + self.args[1].toC()) + + elif self.op == 'imul32_lo': + return 'imul_lo_op_%s(%s, %s)' %( + self.args[0].get_size(), + self.args[0].toC(), + self.args[1].toC()) + elif self.op == 'imul32_hi': + return 'imul_hi_op_%s(%s, %s)' %( + self.args[0].get_size(), + self.args[0].toC(), + self.args[1].toC()) + + elif self.op == '*hi': + return 'mul_hi_op(%s, %s, %s)' %( + self.args[0].get_size(), + self.args[0].toC(), + self.args[1].toC()) + + elif self.op == 'umul32_hi': + return 'mul_hi_op(%s, %s, %s)' %( + self.args[0].get_size(), + self.args[0].toC(), + self.args[1].toC()) + elif self.op == 'umul08': + return 'mul_hi_op(%s, %s, %s)' %( + self.args[0].get_size(), + self.args[0].toC(), + self.args[1].toC()) + + elif self.op in ['bsr', 'bsf']: + return 'my_%s(%s, %s)'%(self.op, + self.args[0].toC(), + self.args[1].toC()) + elif self.op in ['imul08']: + return 'my_%s(%s, %s)'%(self.op, + self.args[0].toC(), + self.args[1].toC()) + elif self.op.startswith('cpuid'): + return "%s(%s, %s)"%(self.op, self.args[0].toC(), self.args[1].toC()) + elif self.op.startswith("fcom"): + return "%s(%s, %s)"%(self.op, self.args[0].toC(), self.args[1].toC()) + elif self.op.startswith("fadd"): + return "%s(%s, %s)"%(self.op, self.args[0].toC(), self.args[1].toC()) + else: + print self.op + raise ValueError('unknown op!!', str(self.op)) + + elif len(self.args)==3: + dct_div= {'div8':"div_op", + 'div16':"div_op", + 'div32':"div_op", + 'idiv32':"div_op", #XXX to test + 'rem8':"rem_op", + 'rem16':"rem_op", + 'rem32':"rem_op", + 'irem32':"rem_op", #XXX to test + '<<<c_rez':'rcl_rez_op', + '<<<c_cf':'rcl_cf_op', + '>>>c_rez':'rcr_rez_op', + '>>>c_cf':'rcr_cf_op', + + } + if not self.op in dct_div: + fsdff + + return '(%s(%s, %s, %s, %s) &0x%x)'%(dct_div[self.op], + self.args[0].get_size(), + self.args[0].toC(), + self.args[1].toC(), + self.args[2].toC(), + my_size_mask[self.args[0].get_size()]) + else: + + raise ValueError('not imple', str(self)) + + + +class ExprSlice(Expr): + def __init__(self, arg, start, stop): + self.arg, self.start, self.stop = arg, start, stop + def __str__(self): + return "%s[%d:%d]"%(str(self.arg), self.start, self.stop) + def get_r(self, mem_read=False): + return self.arg.get_r(mem_read) + def get_w(self): + return self.arg.get_w() + def get_size(self): + return self.stop-self.start + def reload_expr(self, g = {}): + arg = self.arg.reload_expr(g) + + return ExprSlice(arg, self.start, self.stop ) + def __contains__(self, e): + if self == e: + return True + for a in self.args: + if a.__contains__(e): + return True + return False + + def replace_expr(self, g = {}): + if self in g: + return g[self] + arg = self.arg.replace_expr(g) + return ExprSlice(arg, self.start, self.stop ) + + def __eq__(self, a): + if not isinstance(a, ExprSlice): + return False + return self.arg == a.arg and self.start == a.start and self.stop == a.stop + + def __hash__(self): + return hash(self.arg)^hash(self.start)^hash(self.stop) + + def toC(self): + return "((%s>>%d) & ((0xFFFFFFFF>>(32-%d))))"%(self.arg.toC(), self.start, self.stop-self.start) + + +class ExprSliceTo(Expr): + def __init__(self, arg, start, stop): + self.arg, self.start, self.stop = arg, start, stop + def __str__(self): + return "%s_to[%d:%d]"%(str(self.arg), self.start, self.stop) + def get_r(self, mem_read=False): + return self.arg.get_r(mem_read) + def get_w(self): + return self.arg.get_w() + def get_size(self): + return self.stop-self.start + def reload_expr(self, g = {}): + if isinstance(self.arg, Expr): + arg = self.arg.reload_expr(g) + else: + arg = self.arg + + return ExprSliceTo(arg, self.start, self.stop ) + def __contains__(self, e): + return self == e or self.arg.__contains__(e) + + def replace_expr(self, g = {}): + if self in g: + return g[self] + arg = self.arg.replace_expr(g) + return ExprSliceTo(arg, self.start, self.stop) + + def __eq__(self, a): + if not isinstance(a, ExprSliceTo): + return False + return self.arg == a.arg and self.start == a.start and self.stop == a.stop + def __hash__(self): + return hash(self.arg)^hash(self.start)^hash(self.stop) + + def toC(self): + return "((%s & (0xFFFFFFFF>>(32-%d))) << %d)"%(self.arg.toC(), self.stop-self.start, self.start) + +class ExprCompose(Expr): + def __init__(self, args): + self.args = args + def __str__(self): + return '('+', '.join([str(x) for x in self.args])+')' + def get_r(self, mem_read=False): + return reduce(lambda x,y:x.union(y.get_r(mem_read)), self.args, set()) + def get_w(self): + return reduce(lambda x,y:x.union(y.get_r(mem_read)), self.args, set()) + def get_size(self): + return max([x.stop for x in self.args]) - min([x.start for x in self.args]) + def reload_expr(self, g = {}): + args = [] + for a in self.args: + if isinstance(a, Expr): + args.append(a.reload_expr(g)) + else: + args.append(a) + + return ExprCompose(args ) + def __contains__(self, e): + if self == e: + return True + for a in self.args: + if a.__contains__(e): + return True + return False + + def replace_expr(self, g = {}): + if self in g: + return g[self] + args = [] + for a in self.args: + args.append(a.replace_expr(g)) + return ExprCompose(args ) + + def __eq__(self, a): + if not isinstance(a, ExprCompose): + return False + if not len(self.args) == len(a.args): + return False + for i, x in enumerate(self.args): + if not x == a.args[i]: + return False + return True + def __hash__(self): + h = 0 + for a in self.args: + h^=hash(a) + return h + + def toC(self): + out = ' | '.join([x.toC() for x in self.args]) + return '('+out+')' + + +class set_expr: + def __init__(self, l = []): + self._list = [] + for a in l: + self.add(a) + + def add(self, a): + astr = str(a) + for x in self._list: + if str(x) == astr: + return + self._list.append(a) + + def discard(self, a): + astr = str(a) + for x in self._list: + if str(x) == astr: + self._list.remove(x) + return True + return False + + def remove(self ,a): + if not self.discard(a): + raise ValueError('value not found %s'%str(a)) + + + def update(self, list_a): + if not isinstance(list_a, list) and not isinstance(list_a, set): + raise ValueError('arg must be list or set') + for a in list_a: + self.add(a) + + def __contains__(self, a): + astr = str(a) + for x in self._list: + if astr == str(x): + return True + return False + def __str__(self): + o = [] + o.append('[') + for x in self._list: + o.append(str(x)) + o.append(']') + return " ".join(o) + + def __repr__(self): + return "set_expr["+", ".join([str(x) for x in self._list])+"]" + + def __iter__(self): + return self._list.__iter__() diff --git a/miasm/expression/expression_eval_abstract.py b/miasm/expression/expression_eval_abstract.py new file mode 100644 index 00000000..7140da1d --- /dev/null +++ b/miasm/expression/expression_eval_abstract.py @@ -0,0 +1,797 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from miasm.expression.expression import * +import struct +import logging +import cPickle +import numpy +from miasm.expression.expression_helper import * + + + +numpy.seterr(over='ignore', under='ignore') + +mymaxuint = {8:0xFFL, + 16:0xFFFFL, + 32:0xFFFFFFFFL, + 64:0xFFFFFFFFFFFFFFFFL + } + + +#expression evaluation in integer domain + +tab_int_size = {int8:8, + uint8:8, + int16:16, + uint16:16, + int32:32, + uint32:32, + int64:64, + uint64:64 + } + +tab_intsize = {8:int8, + 16:int16, + 32:int32, + 64:int64 + } +tab_uintsize ={8:uint8, + 16:uint16, + 32:uint32, + 64:uint64 + } + +tab_u2i = {uint8:int8, + uint16:int16, + uint32:int32} + + +class eval_abs: + dict_size = { + 1:'B', + 2:'H', + 4:'I', + } + + def parity(self, a): + tmp = (a)&0xFFL + cpt = 1 + while tmp!=0: + cpt^=tmp&1 + tmp>>=1 + return cpt + + def my_bsf(self, a, default_val=0): + tmp = 0 + for i in xrange(32): + if a & (1<<i): + return i + + return default_val + def my_bsr(self, a, op_size, default_val = 0): + tmp = 0 + for i in xrange(op_size-1, -1, -1): + if a & (1<<i): + return i + + return default_val + + + def __init__(self, vars, func_read = None, func_write = None, log = None): + self.pool = {} + for v in vars: + self.pool[v] = vars[v] + self.func_read = func_read + self.func_write = func_write + if log == None: + log = logging.getLogger("expr_eval_int") + console_handler = logging.StreamHandler() + console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s")) + log.addHandler(console_handler) + log.setLevel(logging.WARN) + self.log = log + + def to_file(self, f): + if type(f) is str: + f = open(f,"w") + self.log = None + cPickle.dump(self, f) + + @staticmethod + + def from_file(f, g): + if type(f) is str: + f = open(f,"r") + m = cPickle.load(f) + log = logging.getLogger("expr_eval_int") + console_handler = logging.StreamHandler() + console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s")) + log.addHandler(console_handler) + log.setLevel(logging.WARN) + m.log = log + new_pool = {} + for x in m.pool: + + if not str(x) in g: + xx = ExprId(str(x)) + g[str(xx)] = xx + else: + xx = x + + xx = x + print repr(g[str(xx)]), g[str(xx)] + + if isinstance(m.pool[x], Expr): + new_pool[g[str(xx)]] = m.pool[x].reload_expr(g) + else: + new_pool[g[str(xx)]] = m.pool[x] + + m.pool = new_pool + return m + + def find_mem_by_addr(self, e): + for k in self.pool: + if not isinstance(k, ExprMem): + continue + if k.arg != e: + continue + return k + return None + + + def is_mem_in_target(self, e, t): + ex = ExprOp('-', e.arg, t.arg) + ex = expr_simp(self.eval_expr(ex, {})) + if not isinstance(ex, ExprInt): + return None + ptr_diff = int32(ex.arg) + if ptr_diff <0: + return False + if ptr_diff + e.size/8 <= t.size/8: + return True + return False + + def substract_mems(self, a, b): + ex = ExprOp('-', b.arg, a.arg) + ex = expr_simp(self.eval_expr(ex, {})) + if not isinstance(ex, ExprInt): + return None + ptr_diff = int32(ex.arg) + out = [] + if ptr_diff <0: + # [a ] + #[b ]XXX + + sub_size = b.size + ptr_diff*8 + if sub_size >= a.size: + pass + else: + ex = ExprOp('+', a.arg, ExprInt(uint32(sub_size))) + ex = expr_simp(self.eval_expr(ex, {})) + + rest_ptr = ex + rest_size = a.size - sub_size + + val = self.pool[a][sub_size:a.size] + out = [(ExprMem(rest_ptr, rest_size), val)] + else: + #[a ] + #XXXX[b ]YY + + #[a ] + #XXXX[b ] + + out = [] + #part X + if ptr_diff >0: + val = self.pool[a][0:ptr_diff*8] + out.append((ExprMem(a.arg, ptr_diff*8), val)) + #part Y + if ptr_diff*8+b.size <a.size: + + ex = ExprOp('+', b.arg, ExprInt(uint32(b.size/8))) + ex = expr_simp(self.eval_expr(ex, {})) + + rest_ptr = ex + rest_size = a.size - (ptr_diff*8 + b.size) + val = self.pool[a][ptr_diff*8 + b.size:a.size] + out.append((ExprMem(ex, val.get_size()), val)) + + + return out + + #give mem stored overlapping requested mem ptr + def get_mem_overlapping(self, e): + if not isinstance(e, ExprMem): + raise ValueError('mem overlap bad arg') + ov = [] + + for k in self.pool: + if not isinstance(k, ExprMem): + continue + ex = ExprOp('-', k.arg, e.arg) + ex = expr_simp(self.eval_expr(ex, {})) + if not isinstance(ex, ExprInt): + continue + ptr_diff = int32(ex.arg) + if ptr_diff >=0 and ptr_diff < e.size/8: + ov.append((-ptr_diff, k)) + elif ptr_diff <0 and ptr_diff + k.size/8>0: + ov.append((-ptr_diff, k)) + + return ov + + def eval_expr(self, e, eval_cache): + if e.is_term: + return e + if e.is_eval: + return e + ret = self.eval_expr_no_cache(e, eval_cache) + ret.is_eval = True + return ret + + + + def eval_op_plus(self, args, op_size, cast_int): + ret_value = args[0] + args[1] + return ret_value + + def eval_op_minus(self, args, op_size, cast_int): + ret_value = args[0] - args[1] + return ret_value + + def eval_op_mult(self, args, op_size, cast_int): + ret_value = (args[0] * args[1]) + return ret_value + + def eval_op_div(self, args, op_size, cast_int): + a = uint64(args[0]) + b = uint64(args[1]) + c = uint64(args[2]) + if c == 0: + raise ValueError('div by 0') + big = (a<<uint64(op_size))+b + ret_value = big/c + if ret_value>mymaxuint[op_size]:raise ValueError('Divide Error') + return ret_value + + def eval_op_rem(self, args, op_size, cast_int): + a = uint64(args[0]) + b = uint64(args[1]) + c = uint64(args[2]) + if c == 0: + raise ValueError('div by 0') + big = (a<<uint64(op_size))+b + ret_value = big-c*(big/c) + if ret_value>mymaxuint[op_size]:raise ValueError('Divide Error') + return ret_value + + def eval_op_idiv(self, args, op_size, cast_int): + a = uint64(args[0]) + b = uint64(args[1]) + c = int64(tab_u2i[cast_int](args[2])) + if c == 0: + raise ValueError('div by 0') + big = (a<<uint64(op_size))+b + big = tab_intsize[op_size*2](big) + ret_value = big/c + try: + ret_value = tab_u2i[cast_int](ret_value) + except: + raise ValueError('Divide Error') + return ret_value + + def eval_op_irem(self, args, op_size, cast_int): + a = uint64(args[0]) + b = uint64(args[1]) + c = int64(tab_u2i[cast_int](args[2])) + if c == 0: + raise ValueError('div by 0') + big = (a<<uint64(op_size))+b + big = tab_intsize[op_size*2](big) + ret_value = big/c + try: + ret_value = tab_u2i[cast_int](ret_value) + except: + raise ValueError('Divide Error') + ret_value = big-ret_value*c + return ret_value + + def eval_op_mulhi(self, args, op_size, cast_int): + a = uint64(args[0]) + b = uint64(args[1]) + ret_value = (a*b) >> uint64(op_size) + return ret_value + + def eval_op_mullo(self, args, op_size, cast_int): + a = uint64(args[0]) + b = uint64(args[1]) + ret_value = (a*b) & mymaxuint[op_size] + return ret_value + + def eval_op_eq(self, args, op_size, cast_int): + ret_value = [0, 1][int(args[0] == args[1])] + return ret_value + + def eval_op_inf(self, args, op_size, cast_int): + ret_value = [0, 1][int(args[0] < args[1])] + return ret_value + + def eval_op_and(self, args, op_size, cast_int): + ret_value = (args[0] & args[1]) + return ret_value + + def eval_op_or(self, args, op_size, cast_int): + ret_value = (args[0] | args[1]) + return ret_value + + def eval_op_xor(self, args, op_size, cast_int): + ret_value = (args[0] ^ args[1]) + return ret_value + + def eval_op_not(self, args, op_size, cast_int): + ret_value = (args[0] ^ tab_uintsize[op_size](mymaxuint[op_size])) + return ret_value + + def eval_op_rotl(self, args, op_size, cast_int): + r = args[1]&0x1F + r %=op_size + ret_value = ((args[0]<<r) & mymaxuint[op_size]) | ((args[0] & mymaxuint[op_size]) >> (op_size-r)) + return ret_value + + def eval_op_rotr(self, args, op_size, cast_int): + r = args[1]&0x1F + r %=op_size + ret_value = ((args[0] & mymaxuint[op_size])>>r) | ((args[0] << (op_size-r)) & mymaxuint[op_size]) + return ret_value + + def eval_op_rotl_wflag(self, args, op_size, cast_int): + r = args[1]&0x1F + r %=op_size+1 + r = uint64(r) + op_size = uint64(op_size) + tmpa = uint64((args[0]<<1) | args[2]) + rez = (tmpa<<r) | (tmpa >> (op_size+uint64(1)-r)) + return rez + + def eval_op_rotl_wflag_rez(self, args, op_size, cast_int): + return self.eval_op_rotl_wflag(args, op_size, cast_int)>>1 + def eval_op_rotl_wflag_cf(self, args, op_size, cast_int): + return self.eval_op_rotl_wflag(args, op_size, cast_int)&1 + + def eval_op_rotr_wflag(self, args, op_size, cast_int): + r = args[1]&0x1F + r %=op_size+1 + r = uint64(r) + op_size = uint64(op_size) + tmpa = uint64((args[0]<<1) | args[2]) + rez = (tmpa>>r) | (tmpa << (op_size+uint64(1)-r)) + return rez + + def eval_op_rotr_wflag_rez(self, args, op_size, cast_int): + return self.eval_op_rotr_wflag(args, op_size, cast_int)>>1 + def eval_op_rotr_wflag_cf(self, args, op_size, cast_int): + return self.eval_op_rotr_wflag(args, op_size, cast_int)&1 + + def eval_op_lshift(self, args, op_size, cast_int): + r = args[1]#&0x1F + ret_value = ((args[0] &mymaxuint[op_size])<<r) + return ret_value + + def eval_op_rshift(self, args, op_size, cast_int): + r = args[1]#&0x1F + ret_value = ((args[0]&mymaxuint[op_size])>>r) + return ret_value + + def eval_op_arshift(self, args, op_size, cast_int): + r = args[1]#&0x1F + if args[0]>=0: + ret_value = ((args[0]&mymaxuint[op_size])>>r) + else: + ret_value = -((-args[0])>>r) + return ret_value + + + def eval_op_bsf(self, args, op_size, cast_int): + ret_value = self.my_bsf(args[1], args[0]) + return ret_value + + def eval_op_bsr(self, args, op_size, cast_int): + ret_value = self.my_bsr(args[1], op_size, args[0]) + return ret_value + + def eval_op_parity(self, args, op_size, cast_int): + ret_value = self.parity(args[0]) + return ret_value + + def eval_op_int_32_to_double(self, args, op_size, cast_int): + print args[0] + return ExprTop() + b = struct.pack('L', args[0]) + print repr(b) + b = struct.unpack('f', b)[0] + print b + raise ValueError('not impl yet') + ret_value = args[0] + return ret_value + + def objbyid_default0(self, args, op_size, cast_int): + return ExprOp("objbyid_default0", ExprInt(cast_int(args[0]))) + + + + deal_op = {'+':eval_op_plus, + '-':eval_op_minus, + '*':eval_op_mult, + '/div':eval_op_div, + '/rem':eval_op_rem, + '/idiv':eval_op_idiv, + '/irem':eval_op_irem, + '*hi':eval_op_mulhi, + '*lo':eval_op_mullo, + '==':eval_op_eq, + '<':eval_op_inf, + '&':eval_op_and, + '|':eval_op_or, + '^':eval_op_xor, + '!':eval_op_not, + '<<<':eval_op_rotl, + '>>>':eval_op_rotr, + '<<<c_rez':eval_op_rotl_wflag_rez, + '<<<c_cf':eval_op_rotl_wflag_cf, + '<<':eval_op_lshift, + '>>':eval_op_rshift, + 'a>>':eval_op_arshift, + 'bsf':eval_op_bsf, + 'bsr':eval_op_bsr, + 'parity':eval_op_parity, + 'int_32_to_double':eval_op_int_32_to_double, + + #XXX + 'objbyid_default0':objbyid_default0, + } + + op_size_no_check = ['<<<', '>>>', 'a<<', '>>', '<<', + '<<<c_rez', '<<<c_cf', + '>>>c_rez', '>>>c_cf',] + + + def eval_ExprId(self, e, eval_cache = {}): + if not e in self.pool: + return ExprTop(e) + return self.pool[e] + + def eval_ExprInt(self, e, eval_cache = {}): + return e + + def eval_ExprMem(self, e, eval_cache = {}): + a_val = expr_simp(self.eval_expr(e.arg, eval_cache)) + if isinstance(a_val, ExprTop): + #XXX hack test + ee = ExprMem(e.arg, e.size) + ee.is_term = True + return ee + + + a = expr_simp(ExprMem(a_val, size = e.size)) + if a in self.pool: + return self.pool[a] + + tmp = None + #test if mem lookup is known + for k in self.pool: + if not isinstance(k, ExprMem): + continue + if a_val == k.arg: + tmp = k + break + if tmp == None: + + v = self.find_mem_by_addr(a_val) + if not v: + out = [] + ov = self.get_mem_overlapping(a) + off_base = 0 + ov.sort() + ov.reverse() + for off, x in ov: + if off >=0: + m = min(a.get_size(), x.get_size()-off*8) + ee = ExprSlice(self.pool[x], off*8, off*8 + m) + ee = expr_simp(ee) + out.append(ExprSliceTo(ee, off_base, off_base+ee.get_size())) + off_base += ee.get_size() + else: + m = min(a.get_size()+off*8, x.get_size()) + ee = ExprSlice(self.pool[x], 0, m) + ee = expr_simp(ee) + out.append(ExprSliceTo(ee, off_base, off_base+ee.get_size())) + off_base += ee.get_size() + if out: + ee = ExprSlice(ExprCompose(out), 0, a.get_size()) + ee = expr_simp(ee) + return ee + if self.func_read and isinstance(a.arg, ExprInt): + return self.func_read(self, a) + else: + #XXX hack test + a.is_term = True + return a + + #eq lookup + if a.size == k.size: + return self.pool[tmp] + + #bigger lookup + if a.size > k.size: + rest = a.size + ptr = a_val + out = [] + ptr_index = 0 + while rest: + v = self.find_mem_by_addr(ptr) + if v == None: + raise ValueError("cannot find %s in mem"%str(ptr)) + + if (rest-v.size) >=0: + val = self.pool[v] + diff_size = v.size + else: + diff_size = v.size-rest + val = self.pool[v][0:diff_size] + + val = ExprSliceTo(val, ptr_index, ptr_index+diff_size) + + out.append(val) + ptr_index+=diff_size + rest -= diff_size + ptr = expr_simp(self.eval_expr(ExprOp('+', ptr, ExprInt(uint32(v.size/8))), eval_cache)) + e = expr_simp(ExprCompose(out)) + return e + + #part lookup + tmp = expr_simp(ExprSlice(self.pool[tmp], 0, a.size)) + + return tmp + + def eval_ExprOp(self, e, eval_cache = {}): + args = [] + for a in e.args: + b = expr_simp(self.eval_expr(a, eval_cache)) + if isinstance(b, ExprTop): + return ExprTop() + args.append(b) + #Very agresive, but should work + for a in args: + if isinstance(a, ExprTop): + return ExprTop() + + for a in args: + if not isinstance(a, ExprInt): + return ExprOp(e.op, *args) + + args = [a.arg for a in args] + + types_tab = [type(a) for a in args] + if types_tab.count(types_tab[0]) != len(args) and not e.op in self.op_size_no_check: + raise 'invalid cast %s %s'%(str(types_tab), str(args)) + + cast_int = types_tab[0] + op_size = tab_int_size[types_tab[0]] + + + ret_value = self.deal_op[e.op](self, args, op_size, cast_int) + if isinstance(ret_value, Expr): + return ret_value + return ExprInt(cast_int(ret_value)) + + def eval_ExprCond(self, e, eval_cache = {}): + cond = self.eval_expr(e.cond, eval_cache) + src1 = self.eval_expr(e.src1, eval_cache) + src2 = self.eval_expr(e.src2, eval_cache) + + if isinstance(cond, ExprTop): + return ExprCond(e.cond, src1, src2) + + if isinstance(cond, ExprInt): + if cond.arg == 0: + return src2 + else: + return src1 + return ExprCond(cond, src1, src2) + + def eval_ExprSlice(self, e, eval_cache = {}): + arg = expr_simp(self.eval_expr(e.arg, eval_cache)) + if isinstance(arg, ExprTop): + return ExprTop() + + if isinstance(arg, ExprMem): + if e.start == 0 and e.stop == arg.size: + return arg + + return ExprSlice(arg, e.start, e.stop) + if isinstance(arg, ExprTop): + return ExprTop() + if isinstance(arg, ExprId): + return ExprSlice(arg, e.start, e.stop) + if isinstance(arg, ExprInt): + return expr_simp(ExprSlice(arg, e.start, e.stop)) + if isinstance(arg, ExprCompose): + to_add = [] + return ExprSlice(arg, e.start, e.stop) + return ExprSlice(arg, e.start, e.stop) + + def eval_ExprCompose(self, e, eval_cache = {}): + args = [] + for a in e.args: + aa = self.eval_expr(a.arg, eval_cache) + if isinstance(aa, ExprTop): + return ExprTop() + else: + args.append(aa) + for a in args: + if isinstance(a, ExprTop): + return ExprTop() + is_int = True + is_int_cond = 0 + for x in args: + if isinstance(x, ExprInt): + continue + is_int = False + if not isinstance(x, ExprCond) or not (isinstance(x.src1, ExprInt) and isinstance(x.src2, ExprInt)): + is_int_cond+=3 + continue + is_int_cond+=1 + + + if not is_int and is_int_cond!=1: + uu = ExprCompose([ExprSliceTo(a, e.args[i].start, e.args[i].stop) for i, a in enumerate(args)]) + return uu + + if not is_int: + rez = 0L + total_bit = 0 + + for i in xrange(len(e.args)): + if isinstance(args[i], ExprInt): + a = args[i].arg + + mask = (1<<(e.args[i].stop-e.args[i].start))-1 + a&=mask + a<<=e.args[i].start + total_bit+=e.args[i].stop-e.args[i].start + rez|=a + else: + a = args[i] + mask = (1<<(e.args[i].stop-e.args[i].start))-1 + total_bit+=e.args[i].stop-e.args[i].start + mycond, mysrc1, mysrc2 = a.cond, a.src1.arg&mask, a.src2.arg&mask + cond_i = i + + mysrc1|=rez + mysrc2|=rez + + + + if total_bit in tab_uintsize: + return self.eval_expr(ExprCond(mycond, ExprInt(tab_uintsize[total_bit](mysrc1)), ExprInt(tab_uintsize[total_bit](mysrc2))), eval_cache) + else: + raise 'cannot return non rounb bytes rez! %X %X'%(total_bit, rez) + + + + rez = 0L + total_bit = 0 + for i in xrange(len(e.args)): + a = args[i].arg + mask = (1<<(e.args[i].stop-e.args[i].start))-1 + a&=mask + a<<=e.args[i].start + total_bit+=e.args[i].stop-e.args[i].start + rez|=a + if total_bit in tab_uintsize: + return ExprInt(tab_uintsize[total_bit](rez)) + else: + raise 'cannot return non rounb bytes rez! %X %X'%(total_bit, rez) + + def eval_ExprTop(self, e, eval_cache = {}): + return e + + def eval_expr_no_cache(self, e, eval_cache = {}): + c = e.__class__ + deal_class = {ExprId: self.eval_ExprId, + ExprInt: self.eval_ExprInt, + ExprMem: self.eval_ExprMem, + ExprOp: self.eval_ExprOp, + ExprCond:self.eval_ExprCond, + ExprSlice: self.eval_ExprSlice, + ExprCompose:self.eval_ExprCompose, + ExprTop:self.eval_ExprTop, + } + return deal_class[c](e, eval_cache) + + def get_instr_mod(self, exprs): + pool_out = {} + + eval_cache = {} + + for e in exprs: + if not isinstance(e, ExprAff): + raise TypeError('not affect', str(e)) + + src = self.eval_expr(e.src, eval_cache) + if isinstance(e.dst, ExprMem): + a = self.eval_expr(e.dst.arg, eval_cache) + a = expr_simp(a) + #search already present mem + tmp = None + #test if mem lookup is known + tmp = ExprMem(a, e.dst.size) + dst = tmp + if self.func_write and isinstance(dst.arg, ExprInt): + self.func_write(self, dst, src, pool_out) + else: + pool_out[dst] = src + + elif isinstance(e.dst, ExprId): + pool_out[e.dst] = src + elif isinstance(e.dst, ExprTop): + raise ValueError("affect in ExprTop") + else: + raise ValueError("affected zarb", str(e.dst)) + + + return pool_out + + def eval_instr(self, exprs): + tmp_ops = self.get_instr_mod(exprs) + cste_propag = True + mem_dst = [] + for op in tmp_ops: + if isinstance(op, ExprMem): + ov = self.get_mem_overlapping(op) + for off, x in ov: + diff_mem = self.substract_mems(x, op) + del(self.pool[x]) + for xx, yy in diff_mem: + self.pool[xx] = yy + tmp = expr_simp(tmp_ops[op]) + + if isinstance(expr_simp(op.arg), ExprTop): + raise ValueError('xx') + continue + else: + tmp = tmp_ops[op] + tmp = expr_simp(tmp) + + if isinstance(tmp, ExprInt) and isinstance(op, ExprId) and op.name in ['zf','nf', 'pf', 'of', 'cf', 'df']: + tmp = ExprInt(uint32(tmp.arg)) + self.pool[op] = tmp + if isinstance(op, ExprMem): + mem_dst.append(op) + + + return mem_dst + + def get_reg(self, r): + return self.eval_expr(self.pool[r], {}) + + + + + diff --git a/miasm/expression/expression_helper.py b/miasm/expression/expression_helper.py new file mode 100644 index 00000000..c6bcfa8e --- /dev/null +++ b/miasm/expression/expression_helper.py @@ -0,0 +1,646 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from miasm.expression.expression import * + +tab_size_int = {8:uint8, + 16:uint16, + 32:uint32, + 64:uint64, + } + +tab_max_uint = {8:uint8(0xFF), 16:uint16(0xFFFF), 32:uint32(0xFFFFFFFF), 64:uint64(0xFFFFFFFFFFFFFFFFL)} + + +def parity(self, a): + tmp = (a)&0xFFL + cpt = 1 + while tmp!=0: + cpt^=tmp&1 + tmp>>=1 + return cpt + +def merge_sliceto_slice(args): + sources = {} + non_slice = {} + sources_int = {} + for a in args: + if isinstance(a.arg, ExprInt): + sources_int[a.start] = a + elif isinstance(a.arg, ExprSlice): + if not a.arg.arg in sources: + sources[a.arg.arg] = [] + sources[a.arg.arg].append(a) + else: + non_slice[a.start] = a + + + #find max stop to determine size + max_size = None + for a in args: + if max_size == None or max_size < a.stop: + max_size = a.stop + + + + #first simplify all num slices + + final_sources = [] + sorted_s = [] + for x in sources_int.values(): + #mask int + v = x.arg.arg & ((1<<(x.stop-x.start))-1) + x.arg.arg = v + sorted_s.append((x.start, x)) + sorted_s.sort() + while sorted_s: + + start, v = sorted_s.pop() + out = expr_replace(v, {}) + + + while sorted_s: + if sorted_s[-1][1].stop != start: + break + + start = sorted_s[-1][1].start + + a = uint64((int(out.arg.arg) << (out.start - start )) + sorted_s[-1][1].arg.arg) + out.arg = ExprInt(uint32(a)) + sorted_s.pop() + out.start = start + + out_type = tab_size_int[max_size] + out.arg.arg = out_type(out.arg.arg) + final_sources.append((start, out)) + + final_sources_int = final_sources + + #check if same sources have corresponding start/stop + #is slice AND is sliceto + simp_sources = [] + for s, args in sources.items(): + final_sources = [] + sorted_s = [] + for x in args: + sorted_s.append((x.start, x)) + sorted_s.sort() + while sorted_s: + start, v = sorted_s.pop() + out = expr_replace(v, {}) + while sorted_s: + if sorted_s[-1][1].stop != start: + break + if sorted_s[-1][1].arg.stop != out.arg.start: + break + + start = sorted_s[-1][1].start + out.arg.start = sorted_s[-1][1].arg.start + sorted_s.pop() + out.start = start + + final_sources.append((start, out)) + + simp_sources+=final_sources + + simp_sources+= final_sources_int + + for i, v in non_slice.items(): + simp_sources.append((i, v)) + + simp_sources.sort() + + simp_sources = [x[1] for x in simp_sources] + return simp_sources + + +def expr_simp(e): + if e.is_simp: + return e + e = expr_simp_w(e) + e.is_simp = True + return e + +def expr_simp_w(e): + if isinstance(e, ExprTop): + return e + if isinstance(e, ExprInt): + return e + elif isinstance(e, ExprId): + return e + elif isinstance(e, ExprAff): + return ExprAff(expr_simp(e.dst), expr_simp(e.src)) + elif isinstance(e, ExprCond): + c = expr_simp(e.cond) + if isinstance(c, ExprInt): + print e + fdsfsdf + if c == 0: + return expr_simp(e.src2) + else: + return expr_simp(e.src1) + + return ExprCond(expr_simp(e.cond), expr_simp(e.src1), expr_simp(e.src2)) + elif isinstance(e, ExprMem): + if isinstance(e.arg, ExprTop): + return ExprTop() + return ExprMem(expr_simp(e.arg), size = e.size) + elif isinstance(e, ExprOp): + op, args = e.op, list(e.args) + if ExprTop() in args: + return ExprTop() + #int OP int => int + if e.op in ['+', '-', '*', '|', '&', '^', '>>', '<<'] and isinstance(args[0], ExprInt) and isinstance(args[1], ExprInt) : + if args[0].get_size() != args[1].get_size(): + raise ValueError("diff size! %s"%(str(e))) + if e.op == '+': + o = args[0].arg + args[1].arg + elif e.op == '-': + o = args[0].arg - args[1].arg + elif e.op == '*': + o = args[0].arg * args[1].arg + elif e.op == '|': + o = args[0].arg | args[1].arg + elif e.op == '&': + o = args[0].arg & args[1].arg + elif e.op == '^': + o = args[0].arg ^ args[1].arg + elif e.op == '>>': + o = args[0].arg >> args[1].arg + elif e.op == '<<': + o = args[0].arg << args[1].arg + else: + raise ValueError("zarb op %s"%str(e)) + z = ExprInt(tab_size_int[args[0].get_size()](o)) + return z + + #int OP xx => xx OP int + if e.op in ['+', '*', '|', '&', '^']: + if isinstance(e.args[0], ExprInt) and not isinstance(e.args[1], ExprInt): + op, args= e.op, [e.args[1], e.args[0]] + #A+0 =>A + if op in ['+', '-', '|', "^", "<<", ">>"]: + if isinstance(args[0], ExprInt) and args[0].arg == 0 and not op in ['-', "<<", ">>"]: + return expr_simp(args[1]) + if isinstance(args[1], ExprInt) and args[1].arg == 0: + return expr_simp(args[0]) + + #A&0 =>0 + if op in ['&']: + if isinstance(args[1], ExprInt) and args[1].arg == 0: + return args[1] + + #A-(-123) =>A+123 + if op == '-' and isinstance(args[1], ExprInt) and int32(args[1].arg)<0 : + op = '+' + args[1] = ExprInt(-args[1].arg) + + #A+(-123) =>A-123 + if op == '+' and isinstance(args[1], ExprInt) and int32(args[1].arg)<0 : + op = '-' + args[1] = ExprInt(-args[1].arg) + #fdsfs + #A+3+2 => A+5 + if op in ['+', '-'] and isinstance(args[1], ExprInt) and isinstance(args[0], ExprOp) and args[0].op in ['+', '-'] and isinstance(args[0].args[1], ExprInt): + op1 = op + op2 = args[0].op + if op1 == op2: + op = op1 + args1 = args[0].args[1].arg + args[1].arg + else: + op = op2 + args1 = args[0].args[1].arg - args[1].arg + + + #if op == '-': + # args1 = -args1 + args0 = args[0].args[0] + args = [args0, ExprInt(args1)] + + #0 - (a-b) => b-a + if op == '-' and isinstance(args[0], ExprInt) and args[0].arg == 0 and isinstance(args[1], ExprOp) and args[1].op == "-": + return expr_simp(args[1].args[1] - args[1].args[0]) + + #a<<< x <<< y => a <<< (x+y) (ou <<< >>>) + if op in ['<<<', '>>>'] and isinstance(args[1], ExprInt) and isinstance(args[0], ExprOp) and args[0].op in ['<<<', '>>>'] and isinstance(args[0].args[1], ExprInt): + op1 = op + op2 = args[0].op + if op1 == op2: + op = op1 + args1 = args[0].args[1].arg + args[1].arg + else: + op = op2 + args1 = args[0].args[1].arg - args[1].arg + + args0 = args[0].args[0] + args = [args0, ExprInt(args1)] + + + #a >>> 0 => a (ou <<<) + if op in ['<<<', '>>>'] and isinstance(args[1], ExprInt) and args[1].arg == 0: + e = expr_simp(args[0]) + return e + + #((a >>> b) <<< b) => a + if op in ['<<<', '>>>'] and isinstance(args[0], ExprOp) and args[0].op in ['<<<', '>>>'] and args[1] == args[0].args[1]: + oo = op, args[0].op + if oo in [('<<<', '>>>'), ('>>>', '<<<')]: + + e = expr_simp(args[0].args[0]) + return e + + + #( a + int1 ) - (b+int2) => a - (b+ (int1-int2)) + if op in ['+', '-'] and isinstance(args[0], ExprOp) and args[0].op in ['+', '-'] and isinstance(args[1], ExprOp) and args[1].op in ['+', '-'] and isinstance(args[0].args[1], ExprInt) and isinstance(args[1].args[1], ExprInt): + op1 = op + op2 = args[0].op + op3 = args[1].op + + if op1 == op2: + m_op = "+" + else: + m_op = "-" + e = ExprOp(op1, + args[0].args[0], + ExprOp(m_op, + ExprOp(op3, + args[1].args[0], + args[1].args[1] + ), + args[0].args[1] + ) + ) + e = expr_simp(e) + + return e + + #(a - (a + XXX)) => 0-XXX + if op in ['-'] and isinstance(args[1], ExprOp) and args[1].op in ['+', '-'] and args[1].args[0] == args[0]: + if op == args[1].op: + m_op = "+" + else: + m_op = "-" + + z = ExprInt(tab_size_int[args[1].args[1].get_size()](0)) + e = ExprOp(m_op, + z, + args[1].args[1]) + e = expr_simp(e) + + return e + + + #((a +- XXX) -a) => 0+-XXX + if op in ['-'] and isinstance(args[0], ExprOp) and args[0].op in ['+', '-'] and args[0].args[0] == args[1]: + m_op = args[0].op + + z = ExprInt(tab_size_int[args[0].args[1].get_size()](0)) + e = ExprOp(m_op, + z, + args[0].args[1]) + e = expr_simp(e) + + return e + + # ((a ^ b) ^ a) => b (or commut) + if op in ['^'] and isinstance(args[0], ExprOp) and args[0].op in ['^']: + rest_a = None + if args[0].args[0] == args[1]: + rest_a = args[0].args[1] + elif args[0].args[1] == args[1]: + rest_a = args[0].args[0] + if rest_a != None: + e = expr_simp(rest_a) + return e + # (a ^ (a ^ b) ) => b (or commut) + if op in ['^'] and isinstance(args[1], ExprOp) and args[1].op in ['^']: + rest_a = None + if args[1].args[0] == args[0]: + rest_a = args[1].args[1] + elif args[1].args[1] == args[0]: + rest_a = args[1].args[0] + if rest_a != None: + e = expr_simp(rest_a) + return e + + + # ((a + b) - b) => a (or commut) + if op in ['-'] and isinstance(args[0], ExprOp) and args[0].op in ['+']: + rest_a = None + if args[0].args[1] == args[1]: + rest_a = args[0].args[0] + e = expr_simp(rest_a) + return e + + # ((a - b) + b) => a (or commut) + if op in ['+'] and isinstance(args[0], ExprOp) and args[0].op in ['-']: + rest_a = None + if args[0].args[1] == args[1]: + rest_a = args[0].args[0] + e = expr_simp(rest_a) + return e + + # a<<< a.size => a + if op in ['<<<', '>>>'] and isinstance(args[1], ExprInt) and args[1].arg == args[0].get_size(): + return expr_simp(args[0]) + + #!!a => a + if op == '!' and isinstance(args[0], ExprOp) and args[0].op == '!': + new_e = args[0].args[0] + return expr_simp(new_e) + + #! (!X + int) => X - int + if op == '!' and isinstance(args[0], ExprOp) and args[0].op in ['+', '-'] and isinstance(args[0].args[0], ExprOp) and args[0].args[0].op == '!': + if args[0].op == '+': + op = '-' + else: + op = '+' + return expr_simp(ExprOp(op, args[0].args[0].args[0], args[0].args[1])) + + # ((a (op1+-) int) (op2+-) b) => ((a (op2) b) op1 int)) + if op in ['+', '-'] and isinstance(args[0], ExprOp) and args[0].op in ['+', '-'] and not isinstance(args[1], ExprInt) and args[0].op in ['+', '-'] and isinstance(args[0].args[1], ExprInt): + op1 = op + op2 = args[0].op + e = ExprOp(op2, + ExprOp(op1, + args[0].args[0], + args[1]) + , + args[0].args[1]) + return expr_simp(e) + + + if op == "&" and isinstance(args[0], ExprOp) and args[0].op == '!' and isinstance(args[1], ExprOp) and args[1].op == '!' and isinstance(args[0].args[0], ExprOp) and args[0].args[0].op == '&' and isinstance(args[1].args[0], ExprOp) and args[1].args[0].op == '&': + + ##############1 + a1 = args[0].args[0].args[0] + if isinstance(a1, ExprOp) and a1.op == '!': + a1 = a1.args[0] + elif isinstance(a1, ExprInt): + a1 = ExprInt(~a1.arg) + else: + a1 = None + + b1 = args[0].args[0].args[1] + if isinstance(b1, ExprOp) and b1.op == '!': + b1 = b1.args[0] + elif isinstance(b1, ExprInt): + b1 = ExprInt(~b1.arg) + else: + b1 = None + + + a2 = args[1].args[0].args[0] + b2 = args[1].args[0].args[1] + + + if a1 != None and b1 != None and a1 == a2 and b1 == b2: + new_e = ExprOp('^', a1, b1) + return expr_simp(new_e) + + ################2 + a1 = args[1].args[0].args[0] + if isinstance(a1, ExprOp) and a1.op == '!': + a1 = a1.args[0] + elif isinstance(a1, ExprInt): + a1 = ExprInt(~a1.arg) + else: + a1 = None + + b1 = args[1].args[0].args[1] + if isinstance(b1, ExprOp) and b1.op == '!': + b1 = b1.args[0] + elif isinstance(b1, ExprInt): + b1 = ExprInt(~b1.arg) + else: + b1 = None + + + a2 = args[0].args[0].args[0] + b2 = args[0].args[0].args[1] + + + if a1 != None and b1 != None and a1 == a2 and b1 == b2: + new_e = ExprOp('^', a1, b1) + return expr_simp(new_e) + + + # (x & mask) >> shift whith mask < 2**shift => 0 + if op == ">>" and isinstance(args[1], ExprInt) and isinstance(args[0], ExprOp) and args[0].op == "&": + if isinstance(args[0].args[1], ExprInt) and 2**args[1].arg >= args[0].args[1].arg: + return ExprInt(tab_size_int[args[0].get_size()](0)) + + #! (compose a b c) => (compose !a !b !c) + if op == '!' and isinstance(args[0], ExprCompose): + args = [ExprSliceTo(ExprOp('!', x.arg), x.start, x.stop) for x in args[0].args] + new_e = ExprCompose(args) + return expr_simp(new_e) + #!a[0:X] => (!a)[0:X] + if op == '!' and isinstance(args[0], ExprSlice): + new_e = ExprSlice(ExprOp('!', args[0].arg), args[0].start, args[0].stop) + return expr_simp(new_e) + + + #! int + if op == '!' and isinstance(args[0], ExprInt): + a = args[0] + e = ExprInt(tab_max_uint[a.get_size()]^a.arg) + return e + + #a^a=>0 | a-a =>0 + if op in ['^', '-'] and args[0] == args[1]: + tmp = ExprInt(tab_size_int[args[0].get_size()](0)) + return tmp + + #a & a => a or a | a => a + if op in ['&', '|'] and args[0] == args[1]: + return expr_simp(args[0]) + # int == int => 0 or 1 + if op == '==' and isinstance(args[0], ExprInt) and isinstance(args[1], ExprInt): + if args[0].arg == args[1].arg: + return ExprInt(tab_size_int[args[0].get_size()](1)) + else: + return ExprInt(tab_size_int[args[0].get_size()](0)) + #( a|int == 0) => 0 wirh int != 0 + if op == '==' and isinstance(args[1], ExprInt) and args[1].arg ==0 : + if isinstance(args[0], ExprOp) and args[0].op == '|' and isinstance(args[0].args[1], ExprInt) and \ + args[0].args[1].arg != 0: + return ExprInt(tab_size_int[args[0].get_size()](0)) + + + if op == 'parity' and isinstance(args[0], ExprInt): + fsdfsdf + return ExprInt(tab_size_int[args[0].get_size()](parity(args[0].arg))) + + new_e = ExprOp(op, *[expr_simp(x) for x in args]) + if new_e == e: + return new_e + else: + return expr_simp(new_e) + + #Slice(int) => new_int + elif isinstance(e, ExprSlice): + arg = expr_simp(e.arg) + + if isinstance(arg, ExprTop): + return ExprTop() + elif e.start == 0 and e.stop == 32 and arg.get_size() == 32: + return arg + + elif isinstance(arg, ExprInt): + total_bit = e.stop-e.start + mask = uint64((uint64(1)<<(e.stop-e.start))-1) + if total_bit in tab_size_int: + return ExprInt(tab_size_int[total_bit]((uint64((arg.arg)>>e.start)) & mask)) + else: + return ExprInt(type(arg.arg)((uint64((arg.arg)>>e.start)) & mask)) + elif isinstance(arg, ExprSlice): + if e.stop-e.start > arg.stop-arg.start: + raise ValueError('slice in slice: getting more val', str(e)) + + new_e = ExprSlice(expr_simp(arg.arg), e.start + arg.start, e.start + arg.start + (e.stop - e.start)) + return expr_simp(new_e) + elif isinstance(arg, ExprCompose): + for a in arg.args: + if a.start <= e.start and a.stop>=e.stop: + new_e = a.arg[e.start-a.start:e.stop-a.start] + new_e = expr_simp(new_e) + return new_e + elif isinstance(arg, ExprOp) and e.start == 0: + #if (op ..)[0:X] and op result is good size, skip slice + if e.stop == arg.get_size(): + return expr_simp(arg) + return ExprSlice(arg, e.start, e.stop) + elif isinstance(arg, ExprMem) and e.start == 0 and arg.size == e.stop: + e = expr_simp(arg) + return e + #XXXX hum, is it safe? + elif isinstance(arg, ExprMem) and e.start == 0 and arg.size > e.stop and e.stop %8 == 0: + e = expr_simp(ExprMem(e.arg.arg, size = e.stop)) + return e + + + + + return ExprSlice(arg, e.start, e.stop) + elif isinstance(e, ExprSliceTo): + if isinstance(e.arg, ExprTop): + return ExprTop() + if isinstance(e.arg, ExprSlice) and e.arg.start == 0: + return expr_simp(ExprSliceTo(expr_simp(e.arg.arg), e.start, e.stop)) + + #(.., a[0:X], ..) _to[Y:Z] with X > Z-Y => a[0:X]_to[Y:Z] + if isinstance(e.arg, ExprCompose) and len(e.arg.args) >1: + s = e.get_size() + for a in e.arg.args: + if a.start == 0 and a.stop >= s: + return expr_simp(ExprSliceTo(ExprCompose([a]), e.start, e.stop)) + + + + return ExprSliceTo(expr_simp(e.arg), e.start, e.stop) + elif isinstance(e, ExprCompose): + #(.., a_to[x:y], a[:]_to[y:z], ..) => (.., a[x:z], ..) + e = ExprCompose([expr_simp(x) for x in e.args]) + args = [] + i = -1 + simp = False + while i+1 < len(e.args): + i+=1 + if not args: + args.append(e.args[i]) + continue + if args[-1].stop != e.args[i].start: + continue + if not isinstance(e.args[i].arg, ExprSlice): + continue + if isinstance(args[-1].arg, ExprSlice): + a = args[-1] + else: + a = ExprSliceTo(ExprSlice(args[-1].arg, 0, args[-1].arg.get_size()), args[-1].start, args[-1].stop) + if a.arg.arg != e.args[i].arg.arg: + continue + if a.stop != e.args[i].start: + continue + args[-1] = ExprSliceTo(e.args[i].arg.arg, a.start, e.args[i].stop) + simp = True + + if simp: + return expr_simp(ExprCompose(args)) + + + + all_top = True + for a in e.args: + if not isinstance(a, ExprTop): + all_top = False + break + if all_top: + return ExprTop() + if ExprTop() in e.args: + return ExprTop() + + args = merge_sliceto_slice(e.args) + if len(args) == 1: + a = args[0] + if isinstance(a.arg, ExprInt): + if a.arg.get_size() != a.stop: + print a, a.arg.get_size(), a.stop + raise ValueError("cast in compose!", e) + return a.arg + + uu = expr_simp(a.arg) + return uu + if len(args) != len(e.args): + return expr_simp(ExprCompose(args)) + else: + return ExprCompose(args) + + else: + raise 'bad expr' + + +def expr_cmp(e1, e2): + return str(e1) == str(e2) + +#replace id by another in expr +def expr_replace(e, repl): + if isinstance(e, ExprInt): + return e + elif isinstance(e, ExprId): + if e in repl: + return repl[e] + return e + elif isinstance(e, ExprAff): + return ExprAff(expr_replace(e.dst, repl), expr_replace(e.src, repl)) + elif isinstance(e, ExprCond): + return ExprCond(expr_replace(e.cond, repl), expr_replace(e.src1, repl), expr_replace(e.src2, repl)) + elif isinstance(e, ExprMem): + return ExprMem(expr_replace(e.arg, repl), size = e.size) + elif isinstance(e, ExprOp): + return ExprOp(e.op, *[expr_replace(x, repl) for x in e.args]) + elif isinstance(e, ExprSlice): + return ExprSlice(expr_replace(e.arg, repl), e.start, e.stop) + elif isinstance(e, ExprSliceTo): + return ExprSliceTo(expr_replace(e.arg, repl), e.start, e.stop) + elif isinstance(e, ExprCompose): + return ExprCompose([expr_replace(x, repl) for x in e.args]) + else: + raise 'bad expr' + + + diff --git a/miasm/graph/__init__.py b/miasm/graph/__init__.py new file mode 100644 index 00000000..fbabaacf --- /dev/null +++ b/miasm/graph/__init__.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# diff --git a/miasm/graph/graph_qt.py b/miasm/graph/graph_qt.py new file mode 100755 index 00000000..c47159c7 --- /dev/null +++ b/miasm/graph/graph_qt.py @@ -0,0 +1,806 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +import sys +import math +from PyQt4 import QtGui +from PyQt4 import QtCore + + +from PyQt4.Qt import QTextEdit +from PyQt4.Qt import QPlainTextEdit +from PyQt4.Qt import QMouseEvent +from PyQt4.Qt import QTextCursor +from PyQt4.Qt import QEvent +from PyQt4.Qt import Qt + +app = None +from grandalf.graphs import * +from grandalf.layouts import SugiyamaLayout, VertexViewer +from grandalf.routing import * + +from miasm.core import asmbloc +def __init__(self, w = 40, h = 40, data = None): + self.w = w + self.h = h +VertexViewer.__init__ = __init__ + +class HighlightingRule(): + def __init__( self, pattern, format ): + self.pattern = pattern + self.format = format + + +def gen_syntax_rules(): + highlightingRules = [] + number = QtGui.QTextCharFormat() + label = QtGui.QTextCharFormat() + my_id = QtGui.QTextCharFormat() + highlight_word = QtGui.QTextCharFormat() + + + # hex number + brushg = QtGui.QBrush( Qt.green, Qt.SolidPattern ) + pattern = QtCore.QRegExp( "0x[0-9a-fA-F]+" ) + pattern.setMinimal( False ) + number.setForeground( brushg ) + rule = HighlightingRule( pattern, number ) + highlightingRules.append( rule ) + + + pattern = QtCore.QRegExp( "\b[0-9]+\b" ) + pattern.setMinimal( False ) + number.setForeground( brushg ) + rule = HighlightingRule( pattern, number ) + highlightingRules.append( rule ) + + + #label + brushb = QtGui.QBrush( Qt.blue, Qt.SolidPattern ) + pattern = QtCore.QRegExp( "[0-9a-zA-Z_\.]+:$" ) + pattern.setMinimal( False ) + label.setForeground( brushb ) + rule = HighlightingRule( pattern, label ) + highlightingRules.append( rule ) + + #label + brushb = QtGui.QBrush( Qt.blue, Qt.SolidPattern ) + pattern = QtCore.QRegExp( "[0-9a-zA-Z_\.]+:" ) + pattern.setMinimal( False ) + my_id.setForeground( brushb ) + rule = HighlightingRule( pattern, my_id ) + highlightingRules.append( rule ) + + return highlightingRules + + +syntax_rules = gen_syntax_rules() + + +class MyHighlighter( QtGui.QSyntaxHighlighter ): + def __init__( self, parent ): + QtGui.QSyntaxHighlighter.__init__( self, parent ) + self.parent = parent + + + self.highlightingRules = syntax_rules + + + + + + def highlightBlock( self, text ): + for rule in self.highlightingRules: + expression = QtCore.QRegExp( rule.pattern ) + index = expression.indexIn( text ) + while index >= 0: + length = expression.matchedLength() + self.setFormat( index, length, rule.format ) + index = text.indexOf( expression, index + length ) + self.setCurrentBlockState( 0 ) + + +border_l = 10 +font_w = 7 +font_h = 16 +scale_x = 20.6#2.5 +scale_y = 20.6#2.5 + +title_h = font_h +font_size = 8 + +zoom_lvl = 1.0 +pan_lvl = 120 + +mfont = QtGui.QFont("Monospace", 8) + + +def getTextwh(txt): + l = txt.split('\n') + h = len(l) + w = max(map(lambda x:len(x), l)) + return w, h + + +def getTextwh_font(txt, zoom, font): + l = txt.split('\n') + max_c = max(map(lambda x:len("X"+x+"X"), l)) + w_max = -1 + + r = QtGui.QFontMetrics(font).boundingRect(QtCore.QRect(), 0, txt) + w_max, h_max = r.width(), r.height() + return w_max+30, h_max+20+len(l)*1 + + +class graph_edge(QtGui.QGraphicsItem): + def __init__(self, min_x, min_y, max_x, max_y, pts, color, end_angle, my_splines): + QtGui.QGraphicsItem.__init__(self) + self.min_x = min_x + self.min_y = min_y + self.max_x = max_x + self.max_y = max_y + self.pts = pts + self.color = color + self.setZValue(-1) + self.end_angle = end_angle + self.my_splines = my_splines + def boundingRect(self): + return QtCore.QRectF(self.min_x, self.min_y, self.max_x, self.max_y) + + def paint(self, painter, option, unused_widget): + painter.setPen(self.color) + brush = QtGui.QBrush(self.color) + brush.setStyle(QtCore.Qt.SolidPattern) + painter.setBrush(brush) + + for i, p1 in enumerate(self.pts[:-1]): + p2 = self.pts[i+1] + painter.drawLine(*(p1 + p2)) + + a = -self.end_angle-math.pi + d_a = 0.3 + p3 = p2[0]+10*math.cos(a-d_a), p2[1]-10*math.sin(a-d_a) + p4 = p2[0]+10*math.cos(a+d_a), p2[1]-10*math.sin(a+d_a) + p5 = p2 + + + painter.drawPolygon(QtCore.QPoint(*p2), QtCore.QPoint(*p3), QtCore.QPoint(*p4), QtCore.QPoint(*p5) ) + +class node_asm_bb(QTextEdit): + def __init__(self, txt, mainwin): + self.txt = txt + self.mainwin = mainwin + QTextEdit.__init__(self) + self.setText(self.txt) + self.setFont(mfont) + self.setReadOnly(True) + + + + + + def setpos(self, x, y, w, h): + self.p_x = x + self.p_y = y + self.p_w = w + self.p_h = h + + self.setFixedWidth(self.p_w) + self.setFixedHeight(self.p_h) + + self.move(self.p_x, self.p_y) + self.setFont(mfont) + self.setCurrentFont(mfont) + + + def get_word_under_cursor(self): + cursor = self.textCursor() + cursor.clearSelection() + a, b = cursor.selectionStart () , cursor.selectionEnd () + print a, b + #if only click, get word + cut_char = [' ', "\t", "\n"] + if a == b: + while not self.txt[a] in cut_char: + a-=1 + if a <0: + break + a +=1 + + while b <len(self.txt) and not self.txt[b] in cut_char: + b+=1 + print a, b + print self.txt[a:b] + w = self.txt[a:b] + return w + + def mousePressEvent(self, event): + + if event.button() == Qt.RightButton: + # Rewrite the mouse event to a left button event so the cursor is + # moved to the location of the pointer. + event = QMouseEvent(QEvent.MouseButtonPress, event.pos(), + Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) + + QTextEdit.mousePressEvent(self, event) + cursor = self.textCursor() + + + def mouseDoubleClickEvent(self,mouseEvent): + print "DOUBLE" + w = self.get_word_under_cursor() + app.postEvent(self.mainwin,MyEvent(w)) + + def contextMenuEvent(self, event): + global app + w = self.get_word_under_cursor() + menu = QtGui.QMenu(self) + goto_ad = menu.addAction("sel: "+w) + goto_ad.triggered.connect(lambda:app.postEvent(self.mainwin,MyEvent(w))) + + menu.addAction("Copy") + menu.addAction("Paste") + menu.exec_(event.globalPos()) + + def paintEvent(self, e): + if self.mainwin.view.graphicsView.zoom > -600: + QTextEdit.paintEvent(self, e) + + + + +class View(QtGui.QFrame): + + def __init__(self, name, parent=None): + QtGui.QFrame.__init__(self, parent) + + self.setFrameStyle(QtGui.QFrame.Sunken | QtGui.QFrame.StyledPanel) + + self.graphicsView= myQGraphicsView(parent) + self.graphicsView.setRenderHint(QtGui.QPainter.Antialiasing, False) + self.graphicsView.setDragMode(QtGui.QGraphicsView.RubberBandDrag) + self.graphicsView.setViewportUpdateMode( + QtGui.QGraphicsView.SmartViewportUpdate) + + size = self.style().pixelMetric(QtGui.QStyle.PM_ToolBarIconSize) + iconSize = QtCore.QSize(size, size) + + # Label layout + labelLayout = QtGui.QHBoxLayout() + self.label = QtGui.QLabel(name) + self.antialiasButton = QtGui.QToolButton() + self.antialiasButton.setText("Antialiasing") + self.antialiasButton.setCheckable(True) + self.antialiasButton.setChecked(False) + + # No openGlButton + # No printButton + + labelLayout.addWidget(self.label) + labelLayout.addStretch() + labelLayout.addWidget(self.antialiasButton) + + topLayout = QtGui.QGridLayout() + topLayout.addLayout(labelLayout, 0, 0) + topLayout.addWidget(self.graphicsView, 1, 0) + self.setLayout(topLayout) + + self.connect(self.antialiasButton, QtCore.SIGNAL("toggled(bool)"), + self.toggleAntialiasing) + self.setupMatrix() + + def view(self): + return self.graphicsView + + def resetView(self): + self.setupMatrix() + self.graphicsView.ensureVisible(QtCore.QRectF(0, 0, 0, 0)) + + def setupMatrix(self): + scale = pow(2.0, 0) + + matrix = QtGui.QMatrix() + matrix.scale(scale, scale) + + self.graphicsView.setMatrix(matrix) + + def toggleAntialiasing(self): + self.graphicsView.setRenderHint(QtGui.QPainter.Antialiasing, + self.antialiasButton.isChecked()) + + +class myQGraphicsView(QtGui.QGraphicsView): + def __init__(self, mainwin): + QtGui.QGraphicsView.__init__(self) + self.view = None + self.i_pos = None + self.in_move = False + self.key_ctrl = False + self.zoom = 1.0 + self.ty = 0.0 + self.mainwin = mainwin + + + self.current_node = None + + + def set_view(self, view): + self.view = view + def mouseMoveEvent(self, mouseEvent): + if not self.in_move: + QtGui.QGraphicsView.mouseMoveEvent(self, mouseEvent) + + return + pt = mouseEvent.pos() + x,y = pt.x(), pt.y() + + diff_x, diff_y = self.i_pos[0] - x, self.i_pos[1] - y + scroll_v = self.verticalScrollBar() + scroll_h = self.horizontalScrollBar() + + + pos_v = scroll_v.value() + pos_h = scroll_h.value() + + pos_h += diff_x + pos_v += diff_y + + scroll_v.setValue(pos_v) + scroll_h.setValue(pos_h) + self.i_pos = x, y + + def mousePressEvent(self, mouseEvent): + + QtGui.QGraphicsView.mousePressEvent(self, mouseEvent) + if mouseEvent.button() == QtCore.Qt.LeftButton : + pt = mouseEvent.pos() + i = self.itemAt(pt) + if not i or isinstance(i, graph_edge): + x,y = pt.x(), pt.y() + self.i_pos = x, y + self.in_move = True + elif isinstance(i, QtGui.QGraphicsProxyWidget) and isinstance(i.widget(), node_asm_bb): + #if another node has selected text + #clear it + if self.current_node: + cursor = self.current_node.textCursor() + cursor.clearSelection() + self.current_node.setTextCursor(cursor) + self.current_node = i.widget() + + + + + def mouseReleaseEvent(self, mouseEvent): + QtGui.QGraphicsView.mouseReleaseEvent(self, mouseEvent) + if mouseEvent.button() == QtCore.Qt.LeftButton : + self.in_move = False + + + def keyPressEvent( self, event ): + key = event.key() + print "press", hex(key) + if key == 0x1000021: #ctrl + self.key_ctrl = True + + + elif key == 0x1000005: #enter + if self.mainwin.history_cur < len(self.mainwin.history_ad)-1: + self.mainwin.history_cur +=1 + app.postEvent(self.mainwin,MyEvent(self.mainwin.history_ad[self.mainwin.history_cur])) + + elif key == 0x1000000: #esc + if self.mainwin.history_cur>0: + self.mainwin.history_cur -= 1 + app.postEvent(self.mainwin,MyEvent(self.mainwin.history_ad[self.mainwin.history_cur])) + + elif self.key_ctrl and key in [43, 45]: # - + + if key == 43: + self.zoom +=100 + elif key == 45: + self.zoom -=100 + scale = pow(2.0, (self.zoom /600.0)) + matrix = QtGui.QMatrix() + matrix.scale(scale, scale) + + self.setMatrix(matrix) + + elif key in [0x1000012, 0x1000014]: + if key == 0x1000012: + diff_x = 20 + else: + diff_x = -20 + scroll_h = self.horizontalScrollBar() + pos_h = scroll_h.value() + pos_h += diff_x + scroll_h.setValue(pos_h) + + elif key in [0x1000013, 0x1000015]: + if key == 0x1000013: + diff_y = -20 + else: + diff_y = 20 + scroll_v = self.verticalScrollBar() + pos_v = scroll_v.value() + pos_v += diff_y + scroll_v.setValue(pos_v) + + def keyReleaseEvent( self, event ): + key = event.key() + print "relea", hex(key) + if key == 0x1000021: #ctrl + self.key_ctrl = False + + def wheelEvent(self, event): + #XXX bug if maximize win + mp_x, mp_y = event.pos().x(), event.pos().y() + delta = event.delta() + + scroll_v = self.verticalScrollBar() + + + + if self.key_ctrl: + self.zoom +=delta + else: + pos_v = scroll_v.value() + pos_v -= delta + scroll_v.setValue(pos_v) + + + scale = pow(2.0, (self.zoom /600.0)) + matrix = QtGui.QMatrix() + matrix.scale(scale, scale) + + self.setMatrix(matrix) + + + + + +class MainWindow(QtGui.QWidget): + + def __init__(self, ad = None, all_bloc = [], label = False, dis_callback = None): + QtGui.QWidget.__init__(self, parent = None) + + QtGui.QShortcut(QtGui.QKeySequence("Ctrl+Q"), self, self.close) + self.label = label + self.ad = ad + self.all_bloc = all_bloc + self.dis_callback = dis_callback + self.history_ad = [] + self.history_cur = -1 + + view = View("Graph view", self) + self.view = view + + self.populateScene(ad, all_bloc) + + view.view().setScene(self.scene) + + layout = QtGui.QHBoxLayout() + layout.addWidget(view) + self.setLayout(layout) + + self.setWindowTitle("Miasm Disasm") + + + self.i_pos = None + self.drop_mouse_event = False + + + + def pos2graphpos(self, x, y): + o_x = self.zoom*x + self.add_x + o_y = self.zoom*y + self.add_y + return o_x, o_y + def graphpos2pos(self, x, y): + o_x = (x-self.add_x)/self.zoom + o_y = (y-self.add_y)/self.zoom + return o_x, o_y + + def auto_zoom(self): + if self.max_x == self.min_x: + z1 = 1 + else: + z1 = self.size().width()/(self.max_x - self.min_x) + if self.max_y == self.min_y: + z2 = 1 + else: + z2 = self.size().height()/(self.max_y - self.min_y) + + self.zoom = min(z1, z2) + self.zoom = max(0.1, self.zoom) + #self.zoom*=0.8 + self.zoom_l = math.log(self.zoom) + + print self.min_x + print self.min_y + print self.max_x + print self.max_y + + self.add_x = self.size().width()/2.0 - ((self.max_x+self.min_x)/2.0) * self.zoom + self.add_y = self.size().height()/2.0 - ((self.max_y+self.min_y)/2.0) * self.zoom + + print self.zoom + print self.add_x, self.add_y + for e in self.editor.values(): + e.zoom(self.zoom) + + + + + def graph_from_asmbloc(self, ad, all_bloc): + V = {} + E = [] + for b in all_bloc: + if self.label: + V[b.label] = Vertex(str(b.label.name) +":\n"+"\n".join(["%.8X "%x.offset + str(x) for x in b.lines])) + else: + V[b.label] = Vertex(str(b.label.name) +":\n"+"\n".join([str(x) for x in b.lines])) + for b in all_bloc: + for c in b.bto: + if not isinstance(c.label, asmbloc.asm_label): + continue + data = QtCore.Qt.black + if c.c_t == asmbloc.asm_constraint.c_to: + if b.lines and b.lines[-1].splitflow(): + data = QtCore.Qt.green + else: + data = QtCore.Qt.blue + else: + data = QtCore.Qt.red + ### + if b.label in V and c.label in V: + E.append(Edge(V[b.label], V[c.label], data = data)) + h = asmbloc.getblocby_offset(all_bloc, ad) + if h: + hdr = V[h.label] + else: + hdr = None + V = V.values() + g = Graph(V,E) + return hdr, g, V, E + + def graph_from_v_e(self, ad, all_bloc): + v_hdr, v_dct, edges = all_bloc + V = {} + E = [] + for v_id, c in v_dct.items(): + V[v_id] = Vertex(str(c)) + for a, b in edges: + data = QtCore.Qt.black + E.append(Edge(V[a], V[b], data = data)) + hdr = V[v_hdr] + V = V.values() + g = Graph(V,E) + + + return hdr, g, V, E + + + def add_new_bloc(self, ad, all_bloc = []): + print 'add_new_bloc', ad + if isinstance(ad, str): + if ad.startswith('loc_'): + ad = int(ad[4:12], 16) + elif ad.startswith('0x'): + ad = int(ad, 16) + else: + print 'BAD AD' + return + #print hex(ad) + + if not self.history_ad or (self.history_cur == len(self.history_ad)-1 and ad != self.history_ad[-1]): + print 'add hist' + self.history_ad.append(ad) + self.history_cur +=1 + + + print "AD", hex(ad) + + for b in self.scene_blocs: + b.widget().destroy() + self.scene.removeItem(b) + self.scene_blocs = [] + for e in self.scene_edges: + self.scene.removeItem(e) + self.scene_edges = [] + self.scene.clear() + + if not all_bloc: + print 'DIS', hex(ad) + all_bloc = self.dis_callback(ad) + g = asmbloc.bloc2graph(all_bloc) + open("graph.txt" , "w").write(g) + + + if isinstance(all_bloc, list): + hdr, g, V, E = self.graph_from_asmbloc(ad, all_bloc) + else: + hdr, g, V, E = self.graph_from_v_e(ad, all_bloc) + index = 0 + + print 'g ok' + print 'vertex: ', len(g.C), len(g.C[index].sV), 'edges:', len(g.C[index].sE) + print 'hdr', hdr + + nn = node_asm_bb("toto", self) + mfont = nn.currentFont() + class defaultview(object): + def __init__(self, data = None): + self.data = data + if not data: + self.w, self.h = 80,40 + else: + self.data = self.data.replace('\t', ' '*4) + s = self.data.split('\n') + w, h = getTextwh_font(self.data, 1, mfont) + self.h = h + self.w = w + + self.l = [] + l = [] + def setpath(self, l): + self.l = l + for v in V: v.view = defaultview(v.data) + for e in E: e.view = defaultview() + min_x = None + min_y = None + max_pos_x = 0 + max_pos_y = 0 + + for index in xrange(len(g.C)): + + gr = g.C[index] + + if False:#dr and hdr in g.C[index].sV: + r = [hdr] + else: + r = filter(lambda x: len(x.e_in())==0, gr.sV) + if not r: + print 'no roots!' + r = [gr.sV.o[0]] + r.sort() + + L = g.C[index].get_scs_with_feedback(r) + + sug = SugiyamaLayout(g.C[index]) + sug.xspace = 40 + sug.yspace = 40 + + sug.init_all(roots=r,inverted_edges=filter(lambda x:x.feedback, g.C[index].sE)) + sug.route_edge = route_with_nurbs + sug.draw(1) + + min_pos_x = None + #compute min pos x + for n in g.C[index].sV: + pos = n.view.xy + if min_pos_x == None or pos[0] - n.view.w/2 < min_pos_x: + min_pos_x = pos[0]- n.view.w/2 + + + new_max_pos_x = max_pos_x + first_pos = None + for n in g.C[index].sV: + pos = n.view.xy + if not first_pos: + first_pos = pos + + e = node_asm_bb(n.data, self) + e.h = MyHighlighter(e) + p_x = pos[0] - n.view.w/2 + max_pos_x - min_pos_x + p_y = pos[1] - n.view.h/2 + e.setpos(p_x, p_y, n.view.w, n.view.h) + if p_x + n.view.w > new_max_pos_x: + new_max_pos_x = p_x + n.view.w + wproxy = self.scene.addWidget(e) + self.scene_blocs.append(wproxy) + + e.show() + + for e in g.C[index].sE: + min_x = None + min_y = None + max_x = None + max_y = None + end_angle = None + try: + end_angle = e.view.head_angle + except: + pass + if not e.view.l: + p1 = e.v[0].view.xy + p2 = e.v[1].view.xy + + + for p in [p1, p2]: + if min_x == None or p[0] < min_x: + min_x = p[0] + if max_x == None or p[0] > max_x: + max_x = p[0] + + if min_y == None or p[1] < min_y: + min_y = p[1] + if max_y == None or p[1] > max_y: + max_y = p[1] + pts = [p1, p2] + else: + for p in e.view.l: + x, y = p[0] + max_pos_x, p[1] + p = x, y + + if min_x == None or p[0] < min_x: + min_x = p[0] + if max_x == None or p[0] > max_x: + max_x = p[0] + + if min_y == None or p[1] < min_y: + min_y = p[1] + if max_y == None or p[1] > max_y: + max_y = p[1] + pts = e.view.l + for i, p in enumerate(pts): + x, y = p[0] + max_pos_x - min_pos_x, p[1] + p = x, y + pts[i] = p + e = graph_edge(min_x, min_y, max_x, max_y, pts, e.data, end_angle, e.view.splines) + + self.scene.addItem(e) + self.scene_edges.append(e) + + max_pos_x = new_max_pos_x + + + if first_pos: + self.view.view().centerOn(first_pos[0], first_pos[1]) + + + + def populateScene(self, ad, all_bloc): + self.scene = QtGui.QGraphicsScene() + self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(230, 250, 250, 255))) + self.scene_blocs = [] + self.scene_edges = [] + + self.add_new_bloc(ad, all_bloc) + self.ad = ad + + def customEvent(self,event): + self.add_new_bloc(event.ad) + + +class MyEvent(QEvent): + """ """ + + def __init__(self,ad): + """ """ + QEvent.__init__(self,QEvent.User) + self.ad = ad + + +def graph_blocs(ad, all_bloc, label = False, dis_callback = None): + global app + app = QtGui.QApplication(sys.argv) + g = MainWindow(ad, all_bloc, label, dis_callback) + g.show() + app.exec_() + app.quit() + app = None diff --git a/miasm/tools/__init__.py b/miasm/tools/__init__.py new file mode 100644 index 00000000..fbabaacf --- /dev/null +++ b/miasm/tools/__init__.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# diff --git a/miasm/tools/codenat.py b/miasm/tools/codenat.py new file mode 100644 index 00000000..6711f802 --- /dev/null +++ b/miasm/tools/codenat.py @@ -0,0 +1,160 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +import os +import sys +try: + from Crypto.Hash import MD5 +except ImportError: + print "cannot find crypto MD5, skipping" + +from ctypes import * +from miasm.tools.to_c_helper import * +from miasm.tools.emul_lib import libcodenat_interface + +# interrupt with eip update after instr +EXCEPT_CODE_AUTOMOD = (1<<0) +EXCEPT_SOFT_BP = (1<<1) + +# interrupt with eip at instr +EXCEPT_UNK_MEM_AD = (1<<2) +EXCEPT_THROW_SEH = (1<<3) +EXCEPT_UNK_EIP = (1<<4) +EXCEPT_ACCESS_VIOL = (1<<5) +EXCEPT_INT_DIV_BY_ZERO = (1<<6) +EXCEPT_PRIV_INSN = (1<<7) +EXCEPT_ILLEGAL_INSN = (1<<8) + + + + +EXCEPTION_BREAKPOINT = 0x80000003 +EXCEPTION_ACCESS_VIOLATION = 0xc0000005 +EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094 +EXCEPTION_PRIV_INSTRUCTION = 0xc0000096 +EXCEPTION_ILLEGAL_INSTRUCTION = 0xc000001d + + +PAGE_READ = 1 +PAGE_WRITE = 2 +PAGE_EXEC = 4 + + + +class bloc_nat: + def __init__(self, offset = 0, b = None, module_c = None, log_mn = False, log_regs = False): + self.b = b + self.module_c = module_c + +blocs_nat = {} + +def gen_C_module(c_source): + + lib_name = 'emul_cache/out_'+MD5.new(c_source).hexdigest() + lib_dir = os.path.dirname(os.path.realpath(__file__)) + lib_dir = os.path.join(lib_dir, 'emul_lib') + + a = None + try: + aa = os.stat(lib_name+'.so') + a = cdll.LoadLibrary('./%s.so'%lib_name) + except: + a = None + if a == None: + open(lib_name+'.c', 'w').write(c_source) + + gcc_opts = " -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes " + gcc_opts += " -fPIC -I/usr/include/python2.6 " + os.system('gcc -c '+gcc_opts + ' -L%s -lcodenat -lpython2.6 %s.c -o %s.o'%(lib_dir, lib_name, lib_name)) + + gcc_opts = ' -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions ' + gcc_opts += ' -L%s -lcodenat '%lib_dir + gcc_opts_end = ' -Wl,-rpath,%s '%lib_dir + os.system('gcc ' + gcc_opts + '%s.o -o %s.so '%(lib_name, lib_name) + gcc_opts_end) + + a = cdll.LoadLibrary('%s.so'%lib_name) + + return a + + +def del_bloc_in_range(known_blocs, ad1, ad2): + bloc_out = {} + for ad in known_blocs: + bn = known_blocs[ad] + # XXX no lines in bloc? + if not bn.b.lines: + continue + + if bn.b.lines[0].offset>=ad2 or bn.b.lines[-1].offset + bn.b.lines[-1].l <= ad1: + #bloc_out.append(b) + bloc_out[ad] = bn + else: + #print 'inv bloc', bn.b.label + pass + + return bloc_out + + + + +def vm_save_state(fname): + vmem = vm_get_all_memory() + return vmem + #XXX + + + + +libcntcc = None +def codenat_tcc_load(): + global libcntcc + from distutils.sysconfig import get_python_inc + import emul_lib.libcodenat_tcc as libcntcc + lib_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "emul_lib") + lib_path = os.path.join(lib_dir, 'libcodenat_tcc.so') + libpath = libcodenat_interface.__file__ + libdir = os.path.dirname(libpath) + print libpath + print libdir + libcntcc.tcc_set_emul_lib_path(libdir, libpath, get_python_inc()) + +def codenat_tcc_init(): + global libcntcc + if libcntcc == None: + codenat_tcc_load() + +def codenat_tcc_compil(func_name, func_code): + global libcntcc + c = libcntcc.tcc_compil(func_name, func_code) + return c + +def codenat_tcc_exec(a): + global libcntcc + oo = libcntcc.tcc_exec_bloc(a) + return oo + +def rr(): + pass + +class tcc_code(): + def __init__(self, c): + self.c = c + self.func = lambda :libcntcc.tcc_exec_bloc(self.c) + +def gen_C_module_tcc(f_name, c_source): + mcode = codenat_tcc_compil(f_name, c_source) + return tcc_code(mcode) diff --git a/miasm/tools/emul_helper.py b/miasm/tools/emul_helper.py new file mode 100755 index 00000000..e91e8c1e --- /dev/null +++ b/miasm/tools/emul_helper.py @@ -0,0 +1,679 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +from miasm.arch.ia32_sem import * +from miasm.expression.expression_helper import * +from miasm.core.memory_pool import * +from miasm.core import asmbloc +import StringIO +import zlib + +from miasm.expression.expression_eval_abstract import * + +log_emu_helper = logging.getLogger("emu.helper") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s")) +log_emu_helper.addHandler(console_handler) +log_emu_helper.setLevel(logging.WARN) + +def hexdump(a, offset = 0): + out ="" + for i,c in enumerate(a): + if i%0x10==0: + out+="\n%.8X "%(offset+i) + + out+="%.2X "%ord(c) + return out + + +def tohex(a): + + try: + a = int(a) + except: + return a + if a <0: + a = struct.pack('l', a) + else: + a = struct.pack('L', a) + a = struct.unpack('L', a)[0] + return hex(a) + + +jcc = ['jz', 'je', 'jnz', 'jp', 'jnp', 'jg', 'jge', 'ja', 'jae', 'jb', 'jbe', 'jl', 'jle', 'js', 'jns', 'jo', 'jno', 'loop', 'loopne'] + +def dump_pool(p): + log_emu_helper.error('/-------------\\') + for x in p: + log_emu_helper.error(str(x)+' '+tohex(str(p[x]))) + log_emu_helper.error('\\_____________/') + +def dump_reg(p): + out = " "*20 + for x in [eax, ebx, ecx, edx, esi, edi, esp, ebp, zf]: + if isinstance(p[x], ExprInt): + out+=str(x)+' %.8X '%int(p[x].arg) + else: + out+=str(x)+' %s '%p[x] + + return out + + +def dump_mem(p): + out = [] + todo = [] + kk = p.keys() + kk.sort() + for x in kk: + if isinstance(x, ExprMem): + todo.append(x) + todo.sort() + for x in todo: + out.append('%s %s'%(str(x), str(p[x]))) + + return "\n".join(out) + +def mem_read(evaluator, env, src_address, mem_size): + if not isinstance(src_address, ExprInt): + dump_pool(evaluator.pool) + raise "cannot read", str(src_address) + src_address_l = int(src_address.arg) + try: + + if mem_size == 32: + ret = uint32(env.get_d(src_address_l)) + elif mem_size == 16: + ret = uint16(env.get_w(src_address_l)) + elif mem_size == 8: + ret = uint8(env.get_b(src_address_l)) + else: + raise 'unknown size read', str(src_address.nbytes) + log_emu_helper.debug("=>read @(%X)(%.8X)"%(src_address_l, int(ret))) + return ExprInt(ret) + except: + dump_pool(evaluator.pool) + raise ValueError('read bug at 0x%X'%int(src_address_l)) + +def mem_write(evaluator, env, mem_size, dst_address, src_val, pool_out = None): + if not isinstance(dst_address, ExprInt) or not isinstance(src_val, ExprInt): + dump_pool(evaluator.pool) + raise ValueError("cannot write %s %s"%(str(dst_address), str(src_val))) + dst_address_l = int(dst_address.arg) + src_val = src_val.arg + try: + log_emu_helper.debug("=>write @(%X)(%.8X)"%(dst_address_l, int(src_val))) + if mem_size == 32: + env.set_d(dst_address_l, src_val&0xffffffff) + elif mem_size == 16: + env.set_w(dst_address_l, src_val&0xffff) + elif mem_size == 8: + env.set_b(dst_address_l, src_val&0xff) + else: + raise 'unknown size write', str(dst_address.nbytes) + except: + dump_pool(evaluator.pool) + raise' write bug' + + + + + +###XXX for eval int +def get_instr_expr_args(name, modifs, mnemo_mode, args, my_eip): + for a in args: + if type(a) in [int, long]: + raise ValueError('int deprec in args') + + + if name in ['jmp']: + if isinstance(args[0], ExprInt): + e = mnemo_func[name](ExprOp('+', my_eip, args[0])) + else: + e = mnemo_func[name](*args) + elif name in jcc: + e = mnemo_func[name](my_eip, ExprOp('+', my_eip, args[0])) + elif name in ['call']: + if isinstance(args[0], ExprInt):# or is_imm(args[0]): + e = mnemo_func[name](my_eip, ExprOp('+', my_eip, args[0])) + else: + e = mnemo_func[name](my_eip, args[0]) + else: + e = mnemo_func[name](*args) + return e + +###XXX for eval int +def get_instr_expr(l, my_eip, args = None): + if args==None:args = [] + for x in l.arg: + args.append(dict_to_Expr(x, l.m.modifs, l.mnemo_mode)) + l.arg_expr = args + return get_instr_expr_args(l.m.name, l.m.modifs, l.mnemo_mode, args, my_eip) + + + +###XXX for eval abs +def get_instr_expr_args(name, modifs, mnemo_mode, args, my_eip): + for a in args: + if type(a) in [int, long]: + raise ValueError('int deprec in args') + + + if name in ['jmp']: + if isinstance(args[0], ExprInt): + e = mnemo_func[name](args[0]) + else: + e = mnemo_func[name](*args) + elif name in jcc: + e = mnemo_func[name](my_eip, args[0]) + elif name in ['call']: + e = mnemo_func[name](my_eip, args[0]) + else: + e = mnemo_func[name](*args) + return e + +###XXX for eval abs +def get_instr_expr(l, my_eip, args = None): + if args==None:args = [] + for x in l.arg: + args.append(dict_to_Expr(x, l.m.modifs, l.mnemo_mode)) + l.arg_expr = args + return get_instr_expr_args(l.m.name, l.m.modifs, l.mnemo_mode, args, my_eip) + + + + + +def emul_expr(machine, e, my_eip): + mem_dst = machine.eval_instr(e) + + if eip in machine.pool: + if isinstance(machine.pool[eip], ExprCond): + pass + my_eip = machine.eval_expr(eip, {}) + del machine.pool[eip] + return my_eip, mem_dst + +def emul_bloc(machine, bloc): + return emul_lines(machine, bloc.lines) + + + +def emul_lines(machine, lines): + my_eip = None + for l in lines: + my_eip = ExprInt(uint32(l.offset)) + + args = [] + my_eip.arg+=uint32(l.l) + ex = get_instr_expr(l, my_eip, args) + my_eip, mem_dst = emul_full_expr(ex, l, my_eip, None, machine) + + for k in machine.pool: + machine.pool[k] = expr_simp(machine.pool[k]) + + return my_eip + + + +def emul_imp_init(machine, libbase = 0xCCC00000, malloc_next_ad = 0xEEE00000): + #for loadlibrary & getprocaddress emul + machine.lib_bases = {} + machine.lib_bases_func_index = {} + machine.lib_base = libbase + machine.func_loaded = {} + + #for malloc & free emul + machine.malloc_next_ad = malloc_next_ad; + + +def emul_loadlibrary(machine, env): + my_esp = machine.eval_expr(machine.pool[esp], {}) + libname_ad = env.get_d(my_esp+4) + libname = "" + l = 0 + while True: + libname+=chr(env.get_b(libname_ad+l)) + l+=1 + if libname[-1]=='\x00': + break + + machine.lib_bases[machine.lib_base] = libname + machine.lib_bases_func_index[machine.lib_base] = machine.lib_base+1 + machine.eval_instr(mov(eax, ExprInt(uint32(machine.lib_base)))) + + machine.lib_base+=0x1000 + print "emul loadlib %X, %s"%(libname_ad, libname[:-1]) + log.info("emul loadlib %X, %s"%(libname_ad, libname)) + machine.eval_instr(ret(ExprInt(uint32(4)))) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + return my_eip + +def emul_getprocaddress(machine, env): + my_esp = machine.eval_expr(machine.pool[esp], {}) + libbase_ad = env.get_d(my_esp+4) + funcname_ad = env.get_d(my_esp+8) + funcname = "" + l = 0 + while True: + funcname+=chr(env.get_b(funcname_ad+l)) + l+=1 + if funcname[-1]=='\x00': + break + + log.info("emul getprocaddress %X, %s"%(libbase_ad, funcname)) + print "emul getprocaddress %X, %s"%(libbase_ad, funcname[:-1]) + + if not libbase_ad in machine.lib_bases: + log.debug(machine.lib_bases) + raise 'unknown base lib! %s'%str(libbase_ad) + func_ad = machine.lib_bases_func_index[libbase_ad] + + machine.lib_bases_func_index[libbase_ad]+=1 + machine.eval_instr(mov(eax, ExprInt(uint32(func_ad)))) + + machine.func_loaded[func_ad] = funcname + + machine.eval_instr(ret(ExprInt(uint32(8)))) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + return my_eip + +def hook_import_func(env, imported_func, start_address_hook = 0xAABB0000): + func_hook_ptr = {} + for f in imported_func: + env.set_d(f, start_address_hook) + func_hook_ptr[start_address_hook] = imported_func[f] + start_address_hook+=0x10000 + + return func_hook_ptr + +def dump_imp(machine): + + log_emu_helper.warn('_'*10) + for l in machine.lib_bases: + log_emu_helper.warn("%.8X %s"%(l, machine.lib_bases[l])) + + log_emu_helper.warn('_'*10) + for f in machine.func_loaded: + log_emu_helper.warn("%.8X %s"%(f, machine.func_loaded[f])) + + +def emul_malloc(machine, env): + my_esp = machine.get_reg(esp) + pool_type =env.get_d(my_esp+0x4) + alloc_size =env.get_d(my_esp+0x8) + tag =env.get_d(my_esp+0xc) + + machine.eval_instr(ret(ExprInt(uint32(0xc)))) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + + ret_alloc_ad = machine.malloc_next_ad + m_data = mempool(machine.malloc_next_ad, machine.malloc_next_ad+alloc_size, 'RW', name = "malloc %.8X"%alloc_size) + machine.malloc_next_ad += ((alloc_size+0xFFF)&(~0xFFF)) + + log.warn('alloc(%X) tag %X poolt %X from %X esp %X ret %X:'%(int(alloc_size), int(tag), int(pool_type), int(my_eip), int(my_esp), int(machine.malloc_next_ad))) + machine.eval_instr(mov(eax, ExprInt(uint32(ret_alloc_ad)))) + + env.mems.append(m_data) + log.warn(str(env)) + return my_eip + +def emul_free(machine, env): + my_esp = machine.get_reg(esp) + address_free =env.get_d(my_esp+4) + + machine.eval_instr(ret(ExprInt(uint32(4)))) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + + log.warn('free(%X) from %X esp %X:'%(int(address_free), int(my_eip), int(my_esp))) + + if address_free !=0: + m = env.get_mem_pool(address_free) + if not m: + raise 'cannot find freeing mem!' + env.mems.remove(m) + log.warn(str(env)) + return my_eip + + +def emul_pitfall(machine, env): + raise 'func not impl!' + + +def emul_heapcreate(machine, env): + my_esp = machine.get_reg(esp) + floptions =env.get_d(my_esp+4) + dwinitialsize =env.get_d(my_esp+8) + dwmaximumsize =env.get_d(my_esp+12) + + machine.eval_instr(ret(ExprInt(uint32(12)))) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + + + log.warn('heapcreate(%X %X %X) from %X esp %X ret %X:'%(floptions, dwinitialsize, dwmaximumsize, int(my_eip), my_esp, 0xdeadcafe)) + machine.eval_instr(mov(eax, ExprInt(uint32(0xdeadcafe)))) + + return my_eip + +def emul_heapalloc(machine, env): + my_esp = machine.get_reg(esp) + hheap =env.get_d(my_esp+4) + dwflags =env.get_d(my_esp+8) + alloc_size =env.get_d(my_esp+12) + + machine.eval_instr(ret(ExprInt(uint32(12)))) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + + ret_alloc_ad = machine.malloc_next_ad + m_data = mempool(machine.malloc_next_ad, machine.malloc_next_ad+alloc_size, 'RW', name = "heapalloc %.8X"%alloc_size) + machine.malloc_next_ad += ((alloc_size+0xFFF)&(~0xFFF)) + + log.warn('heapalloc(%X %X %X) from %X esp %X ret %X:'%(hheap, dwflags, alloc_size, int(my_eip), my_esp, machine.malloc_next_ad)) + machine.eval_instr(mov(eax, ExprInt(uint32(ret_alloc_ad)))) + + env.mems.append(m_data) + log.warn(str(env)) + return my_eip + +#VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) +def emul_virtualprotect(machine, env): + my_esp = machine.eval_expr(machine.pool[esp], {}) + lpaddress = env.get_d(my_esp+4) + dwsize = env.get_d(my_esp+8) + flnewprotect = env.get_d(my_esp+12) + lpfloldprotect = env.get_d(my_esp+16) + + #XXX return 1?? + machine.eval_instr(mov(eax, ExprInt(uint32(1)))) + + log.info("emul virtualprotect %X, %X %X %X"%(lpaddress, dwsize, flnewprotect, lpfloldprotect)) + machine.eval_instr(ret(ExprInt(uint32(16)))) + #dump_pool(machine.pool) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + return my_eip + +def emul_virtualalloc(machine, env): + my_esp = machine.get_reg(esp) + lpaddress =env.get_d(my_esp+4) + alloc_size =env.get_d(my_esp+8) + flallocationtype =env.get_d(my_esp+12) + flprotect =env.get_d(my_esp+16) + + machine.eval_instr(ret(ExprInt(uint32(16)))) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + + ret_alloc_ad = machine.malloc_next_ad + m_data = mempool(machine.malloc_next_ad, machine.malloc_next_ad+alloc_size, 'RW', name = "virtualalloc %.8X"%alloc_size) + machine.malloc_next_ad += ((alloc_size+0xFFF)&(~0xFFF)) + + log.warn('virtualalloc(%X %X %X %X) from %X esp %X ret %X:'%(lpaddress, alloc_size, flallocationtype, flprotect, int(my_eip), my_esp, machine.malloc_next_ad)) + machine.eval_instr(mov(eax, ExprInt(uint32(ret_alloc_ad)))) + + env.mems.append(m_data) + log.warn(str(env)) + return my_eip + + +def emul_virtualfree(machine, env): + my_esp = machine.get_reg(esp) + address_free =env.get_d(my_esp+4) + dwsize =env.get_d(my_esp+8) + dwfreetype =env.get_d(my_esp+12) + + + + machine.eval_instr(ret(ExprInt(uint32(12)))) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + + log.warn('virtualfree(%X %X %X) from %X esp %X:'%(address_free, dwsize, swfreetype, int(my_eip), my_esp)) + + if address_free !=0: + m = env.get_mem_pool(address_free) + if not m: + raise 'cannot find freeing mem!' + env.mems.remove(m) + log.warn(str(env)) + return my_eip + + + +def emul_getmodulehandlea(machine, env): + my_esp = machine.eval_expr(machine.pool[esp], {}) + libname_ad = env.get_d(my_esp+4) + libname = "" + l = 0 + while True: + libname+=chr(env.get_b(libname_ad+l)) + l+=1 + if libname[-1]=='\x00': + break + + + machine.eval_instr(ret(ExprInt(uint32(4)))) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + + + log.info("emul loadlib (%X), %s from %X"%(libname_ad, libname, my_eip)) + + if False:#libname.startswith("kernel32.dll"): + machine.eval_instr(mov(eax, ExprInt(uint32(0x7C800000)))) + else: + machine.eval_instr(mov(eax, ExprInt(uint32(0x0)))) + log.warn("unknown lib: %s"%str(libname)) + + log.warn(str(env)) + + return my_eip + +def emul_kddisabledebugger(machine, env): + my_esp = machine.get_reg(esp) + + machine.eval_instr(ret()) + my_eip = machine.eval_expr(machine.pool[eip], {}) + del machine.pool[eip] + + + log.warn('emul_kddisabledebugger from %X esp %X '%(int(my_eip), int(my_esp))) + machine.eval_instr(mov(eax, ExprInt(uint32(0)))) + + log.warn(str(env)) + return my_eip + + + +def sav_machine(machine, env, my_eip, snap_fmt_name): + + print 'SAVE**************tsc: %.10d***************'%machine.pool[tsc1].arg + machine.pool[eip] = my_eip + env_s = StringIO.StringIO() + env.to_file(env_s) + env_s.flush() + fname = snap_fmt_name+".env" + open(fname%(machine.pool[tsc1].arg), 'wb').write(zlib.compress(env_s.getvalue(), 9)) + machine_s = StringIO.StringIO() + machine.to_file(machine_s) + machine_s.flush() + fname = snap_fmt_name+".machine" + open(fname%(machine.pool[tsc1].arg), 'wb').write(zlib.compress(machine_s.getvalue(), 9)) + del machine.pool[eip] + + +def load_machine(snap_fmt_name, step): + + fname = snap_fmt_name+".env" + env_s = StringIO.StringIO(zlib.decompress(open(fname%step, 'rb').read())) + env = mempool_manager.from_file(env_s) + fname = snap_fmt_name+".machine" + machine_s = StringIO.StringIO(zlib.decompress(open(fname%step, 'rb').read())) + machine = eval_int.from_file(machine_s, globals()) + my_eip = machine.pool[eip] + del machine.pool[eip] + print 'LOAD**************tsc: %.10X***************'%machine.pool[tsc1].arg + print "machine eip: %.8X"%int(my_eip.arg) + + return machine, env, my_eip + +def emul_full_expr(e, l, my_eip, env, machine): + if ((not 0xF2 in l.prefix) and (not 0xF3 in l.prefix)) or \ + not l.m.name[:-1] in ["ins", "outs", "movs", "lods", "stos", "cmps", "scas"]: + my_eip, mem_dst = emul_expr(machine, e, my_eip) + else: + #rep mnemo + #XXX HACK 16 bit + if 0x66 in l.prefix and l.m.name[-1]== "d": + raise "not impl 16 bit string" + zf_w = zf in reduce(lambda x,y:x+y, [list(x.get_w()) for x in e], []) + + while True: + + my_ecx = machine.eval_expr(machine.pool[ecx], {}) + if not isinstance(my_ecx, ExprInt):# in tab_int_size:#[int, long]: + raise "cannot eval counter....", str(machine.pool[ecx]) + if l.mnemo_mode== u16: + my_ecx.arg&=0xFFFF + if my_ecx.arg ==0: + break + + my_esi = machine.eval_expr(machine.pool[esi], {}) + my_edi = machine.eval_expr(machine.pool[edi], {}) + tmp,mem_dst = emul_expr(machine, e, my_eip) + + machine.eval_instr(mov(ecx, ExprOp('-', my_ecx, ExprInt(uint32(1))))) + machine.eval_expr(machine.pool[ecx], {}) + + if zf_w : + my_zf = machine.eval_expr(machine.pool[zf], {}) + if 0xF3 in l.prefix and my_zf == 0: + break + if 0xF2 in l.prefix and my_zf == 1: + break + + machine.pool[tsc1].arg+=uint32(1) + + return my_eip, mem_dst + + +def guess_func_destack(all_bloc): + ret_destack = None + for b in all_bloc: + l = b.lines[-1] + if not l.m.name.startswith('ret'): + continue + if len(l.arg) == 0: + a = 0 + elif len(l.arg) ==1: + a = l.arg[0][x86_afs.imm] + else: + continue + if ret_destack!=None: + if a != ret_destack: + print 'found diff ret unstack', ret_destack, a + return None, None + else: + continue + ret_destack = a + + + if ret_destack !=None: + return True, ret_destack + + #try func wrapper + if len(all_bloc)!= 1: + return None, None + l = all_bloc[0].lines[-1] + if not l.m.name.startswith('jmp') or len(l.arg) !=1: + return None, None + + a = l.arg[0] + print hex(l.offset), a, type(a) + + if not x86_afs.imm in a or not x86_afs.ad in a or not a[x86_afs.ad]: + return None, None + + return False, a[x86_afs.imm] + + +def digest_allbloc_instr(all_bloc): + instrs = {} + g = asmbloc.bloc2graph(all_bloc) + open("graph_b.txt" , "w").write(g) + + + #test duplicated blocs + unik_blobs = {} + for b in all_bloc: + if not b.label in unik_blobs: + unik_blobs[b.label] = [] + unik_blobs[b.label].append(b) + + + for lbl, blcs in unik_blobs.items(): + if len(blcs) ==1: + continue + tmp = blcs.pop() + for b in blcs: + if str(tmp) != str(b): + print tmp + print b + raise ValueError('diff bloc in same label') + all_bloc.remove(b) + + for b in all_bloc: + for l in b.lines: + if l.offset in instrs: + log.warn(('zarb: dup instr', (hex(l.offset), str(l)))) + if str(instrs[l.offset][0]) != str(l): + raise ValueError('dup instr@ with different instr', (str(l), str(instrs[l.offset][0]))) + args = [] + ex = get_instr_expr(l, ExprInt(uint32(l.offset+l.l)), args) + + + instrs[l.offset] = (l, ex) + return instrs + + +def x86_machine(): + machine = eval_abs({esp:init_esp, ebp:init_ebp, eax:init_eax, ebx:init_ebx, ecx:init_ecx, edx:init_edx, esi:init_esi, edi:init_edi, + cs:ExprInt(uint32(9)), + zf : init_zf, nf : init_nf, pf : init_pf, + of : init_of, cf : init_cf, tf : init_tf, + i_f: init_i_f, df : init_df, af : init_af, + iopl: init_iopl, nt : init_nt, rf : init_rf, + vm : init_vm, ac : init_ac, vif: init_vif, + vip: init_vip, i_d: init_i_d,tsc1: init_tsc1, + tsc2: init_tsc2, + dr7:ExprInt(uint32(0)), + cr0:init_cr0, + #my_ret_addr:my_ret_addri + + }, + #mem_read_wrap, + #mem_write_wrap, + + ) + return machine diff --git a/miasm/tools/emul_lib/Makefile b/miasm/tools/emul_lib/Makefile new file mode 100644 index 00000000..5365160b --- /dev/null +++ b/miasm/tools/emul_lib/Makefile @@ -0,0 +1,20 @@ +CFLAGS=-Wall -I/usr/include/python2.6 -lpython2.6 +CC = gcc +all: libcodenat.so libcodenat_tcc.so libcodenat_interface.so + +libcodenat_interface.so: libcodenat_interface.c + $(CC) $(CFLAGS) -shared -o $@ $< -lm -lcodenat -L`pwd` -Wl,-rpath,`pwd` + +libcodenat.so: libcodenat.c + $(CC) $(CFLAGS) -shared -o $@ $< -lm + +libcodenat_tcc.so: libcodenat_tcc.c + $(CC) $(CFLAGS) -shared -o $@ $< -ldl /usr/lib/i386-linux-gnu/libtcc.a + + + +test: main.o libcodenat.a + $(CC) $< $(CFLAGS) -L. -L/usr/lib -lcodenat -lpython2.6 + +clean: + rm -f libcodenat.so libcodenat_interface.so libcodenat_interface.o libcodenat.o a.out libcodenat_tcc.o libcodenat_tcc.so diff --git a/miasm/tools/emul_lib/__init__.py b/miasm/tools/emul_lib/__init__.py new file mode 100644 index 00000000..fbabaacf --- /dev/null +++ b/miasm/tools/emul_lib/__init__.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# diff --git a/miasm/tools/emul_lib/libcodenat.c b/miasm/tools/emul_lib/libcodenat.c new file mode 100644 index 00000000..c670224d --- /dev/null +++ b/miasm/tools/emul_lib/libcodenat.c @@ -0,0 +1,1305 @@ +/* +** Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License along +** with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +//#include <Python.h> + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +#include <stdint.h> + +#include "queue.h" +#include "libcodenat.h" + + + + + +struct memory_page_list_head memory_page_pool; +struct code_bloc_list_head code_bloc_pool; + +//#define RAISE(errtype,msg) { PyErr_SetString(errtype,msg); RE_RAISE; } +//#define RE_RAISE { Py_XDECREF(string); return NULL; } +//#define RAISE(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return p;} + +/* +unsigned int eax, ebx, ecx, edx, esi, edi, esp, ebp, eip; +unsigned int zf, nf, pf, of, cf, af, df; + +unsigned int eax_new, ebx_new, ecx_new, edx_new, esi_new, edi_new, esp_new, ebp_new, eip_new; +unsigned int zf_new, nf_new, pf_new, of_new, cf_new, af_new, df_new; +unsigned int tf, i_f, iopl_f, nt, rf, vm, ac, vif, vip, i_d; +unsigned int tf_new, i_f_new, iopl_f_new, nt_new, rf_new, vm_new, ac_new, vif_new, vip_new, i_d_new; + +unsigned int my_tick = 0; + +unsigned int reg_float_control; + +unsigned int cond; + + +unsigned int ds; + + +unsigned int vm_exception_flags = 0; +unsigned int vm_exception_flags_new = 0; + + +unsigned int vm_last_write_ad = 0; +unsigned int vm_last_write_size = 0; +*/ + +vm_cpu_t vmcpu; + +/****************memory manager**************/ + +unsigned int min_page_ad = 0x22000000; + +extern unsigned int *code_addr_tab; + +//LIST_HEAD(memory_page_list_head, memory_page_node) memory_page_pool; +//LIST_HEAD(code_bloc_list_head, code_bloc_node) code_bloc_pool; + + +unsigned int code_bloc_pool_ad_min; +unsigned int code_bloc_pool_ad_max; + +#define MAX_MEMORY_PAGE_POOL_TAB 0x100000 +#define MEMORY_PAGE_POOL_MASK_BIT 12 +#define PAGE_SIZE (1<<MEMORY_PAGE_POOL_MASK_BIT) +struct memory_page_node *memory_page_pool_tab[MAX_MEMORY_PAGE_POOL_TAB]; + + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + + + + + + + + + + + + +void dump_gpregs(void) +{ + printf("eip %.8X eax %.8X ebx %.8X ecx %.8X edx %.8X\nesi %.8X edi %.8X esp %.8X ebp %.8X\nmy_tick %X\n", + vmcpu.eip, vmcpu.eax, vmcpu.ebx, vmcpu.ecx, vmcpu.edx, vmcpu.esi, vmcpu.edi, vmcpu.esp, vmcpu.ebp, + vmcpu.my_tick); +} + +struct memory_page_node * get_memory_page_from_address(unsigned int ad) +{ + struct memory_page_node * mpn; +#if 1 + mpn = memory_page_pool_tab[ad>>MEMORY_PAGE_POOL_MASK_BIT]; + if ( mpn && (mpn->ad <= ad) && (ad < mpn->ad + mpn->size)) + return mpn; + + printf("cannot find address!! %X\n", ad); + dump_memory_page_pool(); + dump_gpregs(); + //exit(-1); + vmcpu.vm_exception_flags |= EXCEPT_ACCESS_VIOL; + + return NULL; +#else + + //printf("search for page ad: %X\n", ad); + LIST_FOREACH(mpn, &memory_page_pool, next){ + if ((mpn->ad <= ad) && (ad < mpn->ad + mpn->size)) + return mpn; + } + printf("cannot find address!! %X\n", ad); + dump_memory_page_pool(); + dump_gpregs(); + //exit(-1); + vmcpu.vm_exception_flags |= EXCEPT_ACCESS_VIOL; + return NULL; +#endif +} + + + + +static inline unsigned long long memory_page_read(unsigned int my_size, unsigned int ad) +{ + struct memory_page_node * mpn; + unsigned char * addr; + unsigned long long ret = 0; + + + mpn = get_memory_page_from_address(ad); + if (!mpn) + return 0; + + if ((mpn->access & PAGE_READ) == 0){ + printf("access to non readable page!! %X\n", ad); + vmcpu.vm_exception_flags |= EXCEPT_ACCESS_VIOL; + return 0; + } + addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad]; + + /* read fits in a page */ + if (ad - mpn->ad + my_size/8 <= mpn->size){ + switch(my_size){ + case 8: + ret = *((unsigned char*)addr)&0xFF; + break; + case 16: + ret = *((unsigned short*)addr)&0xFFFF; + ret = Endian16_Swap(ret); + break; + case 32: + ret = *((unsigned int*)addr)&0xFFFFFFFF; + ret = Endian32_Swap(ret); + break; + case 64: + ret = *((unsigned long long*)addr)&0xFFFFFFFFFFFFFFFFULL; + ret = Endian64_Swap(ret); + break; + default: + exit(0); + break; + + } + } + /* read is multiple page wide */ + else{ + unsigned int new_size = my_size; + printf("read multiple page! %X %X\n", ad, new_size); + dump_memory_page_pool(); + while (new_size){ + ret <<=8; + mpn = get_memory_page_from_address(ad); + if (!mpn) + return 0; + addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad]; + ret = *((unsigned char*)addr)&0xFF; + new_size -= 8; + ad ++; + } + switch(my_size){ + case 8: + ret = ret; + break; + case 16: + ret = Endian16_Swap(ret); + break; + case 32: + ret = Endian32_Swap(ret); + break; + case 64: + ret = Endian64_Swap(ret); + break; + default: + exit(0); + break; + } + } + return ret; +} + +static inline void memory_page_write(unsigned int my_size, unsigned int ad, unsigned long long src) +{ + struct memory_page_node * mpn; + unsigned char * addr; + + mpn = get_memory_page_from_address(ad); + if (!mpn) + return; + + if ((mpn->access & PAGE_WRITE) == 0){ + printf("access to non writable page!! %X\n", ad); + vmcpu.vm_exception_flags |= EXCEPT_ACCESS_VIOL; + + return ; + } + + addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad]; + + /* write fits in a page */ + if (ad - mpn->ad + my_size/8 <= mpn->size){ + switch(my_size){ + case 8: + *((unsigned char*)addr) = src&0xFF; + break; + case 16: + src = Endian16_Swap(src); + *((unsigned short*)addr) = src&0xFFFF; + break; + case 32: + src = Endian32_Swap(src); + *((unsigned int*)addr) = src&0xFFFFFFFF; + break; + case 64: + src = Endian64_Swap(src); + *((unsigned long long*)addr) = src&0xFFFFFFFFFFFFFFFFULL; + break; + default: + exit(0); + break; + } + } + /* write is multiple page wide */ + else{ + printf("write multiple page! %X %X\n", ad, my_size); + dump_memory_page_pool(); + switch(my_size){ + + case 8: + src = src; + break; + case 16: + src = Endian16_Swap(src); + break; + case 32: + src = Endian32_Swap(src); + break; + case 64: + src = Endian64_Swap(src); + break; + default: + exit(0); + break; + } + + while (my_size){ + mpn = get_memory_page_from_address(ad); + if (!mpn) + return; + + addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad]; + *((unsigned char*)addr) = src&0xFF; + my_size -= 8; + ad ++; + } + + } +} + + + +inline void check_write_code_bloc(unsigned int my_size, unsigned int addr) +{ + struct code_bloc_node * cbp; + + vmcpu.vm_last_write_ad = addr; + vmcpu.vm_last_write_size = my_size; + + //if(vmcpu.my_tick> my_tick) + // printf("M_WRITE %2d %.8X %.8X\n", my_size, addr, src); + if (!(addr + my_size/8 <= code_bloc_pool_ad_min || addr >=code_bloc_pool_ad_max)){ + LIST_FOREACH(cbp, &code_bloc_pool, next){ + if ((cbp->ad_start <= addr + my_size/8) && (addr < cbp->ad_stop)){ + printf("self modifying code %.8X %.8X from approx %X\n", addr, my_size, vmcpu.eip); + vmcpu.vm_exception_flags |= EXCEPT_CODE_AUTOMOD; + break; + } + } + } + +} + +void MEM_WRITE(unsigned int my_size, unsigned int addr , unsigned int src) +{ + struct code_bloc_node * cbp; + + vmcpu.vm_last_write_ad = addr; + vmcpu.vm_last_write_size = my_size; + + //if(vmcpu.my_tick> my_tick) + // printf("M_WRITE %2d %.8X %.8X\n", my_size, addr, src); + if (!(addr + my_size/8 <= code_bloc_pool_ad_min || addr >=code_bloc_pool_ad_max)){ + LIST_FOREACH(cbp, &code_bloc_pool, next){ + if ((cbp->ad_start <= addr + my_size/8) && (addr < cbp->ad_stop)){ + printf("self modifying code %.8X %.8X from approx %X\n", addr, my_size, vmcpu.eip); + vmcpu.vm_exception_flags |= EXCEPT_CODE_AUTOMOD; + break; + } + } + } + + memory_page_write(my_size, addr, src); +} + +void MEM_WRITE_08(unsigned int addr , unsigned char src) +{ + check_write_code_bloc(8, addr); + memory_page_write(8, addr, src); +} + +void MEM_WRITE_16(unsigned int addr , unsigned short src) +{ + check_write_code_bloc(16, addr); + memory_page_write(16, addr, src); +} + +void MEM_WRITE_32(unsigned int addr , unsigned int src) +{ + check_write_code_bloc(32, addr); + memory_page_write(32, addr, src); +} + +void MEM_WRITE_64(unsigned int addr , unsigned long long src) +{ + check_write_code_bloc(64, addr); + memory_page_write(64, addr, src); +} + + +unsigned int MEM_LOOKUP(unsigned int my_size, unsigned int addr) +{ + unsigned int ret; + ret = memory_page_read(my_size, addr); + //if(vmcpu.my_tick> my_tick) + //printf("M_READ %2d %.8X %.8X\n", my_size, addr, ret); + return ret; +} + +unsigned char MEM_LOOKUP_08(unsigned int addr) +{ + unsigned char ret; + ret = memory_page_read(8, addr); + return ret; +} + +unsigned short MEM_LOOKUP_16(unsigned int addr) +{ + unsigned short ret; + ret = memory_page_read(16, addr); + return ret; +} + +unsigned int MEM_LOOKUP_32(unsigned int addr) +{ + unsigned int ret; + ret = memory_page_read(32, addr); + return ret; +} + +unsigned long long MEM_LOOKUP_64(unsigned int addr) +{ + unsigned long long ret; + ret = memory_page_read(64, addr); + return ret; +} + + + + +void MEM_WRITE_08_PASSTHROUGH(unsigned int addr, unsigned char src) +{ + *((unsigned char*)addr) = src; +} + +void MEM_WRITE_16_PASSTHROUGH(unsigned int addr, unsigned short src) +{ + *((unsigned short*)addr) = Endian16_Swap(src); +} + +void MEM_WRITE_32_PASSTHROUGH(unsigned int addr, unsigned int src) +{ + *((unsigned int*)addr) = Endian32_Swap(src); +} + +void MEM_WRITE_64_PASSTHROUGH(unsigned int addr, unsigned long long src) +{ + *((unsigned long long*)addr) = Endian64_Swap(src); +} + + +unsigned char MEM_LOOKUP_08_PASSTHROUGH(unsigned int addr) +{ + unsigned char ret; + ret = *((unsigned char*)addr); + return ret; +} + +unsigned short MEM_LOOKUP_16_PASSTHROUGH(unsigned int addr) +{ + unsigned short ret; + ret = *((unsigned short*)addr); + return Endian16_Swap(ret); +} + +unsigned int MEM_LOOKUP_32_PASSTHROUGH(unsigned int addr) +{ + unsigned int ret; + ret = *((unsigned int*)addr); + return Endian32_Swap(ret); +} + +unsigned long long MEM_LOOKUP_64_PASSTHROUGH(unsigned int addr) +{ + unsigned long long ret; + ret = *((unsigned long long*)addr); + return Endian64_Swap(ret); +} + + + +void vm_throw(unsigned long flags) +{ + vmcpu.vm_exception_flags |= flags; +} + +inline unsigned int parity(unsigned int a) +{ + unsigned int tmp, cpt; + + tmp = a&0xFF; + cpt = 1; + while (tmp!=0){ + cpt^=tmp&1; + tmp>>=1; + } + return cpt; +} + + +int shift_right_arith(unsigned int size, int a, unsigned int b) +{ + int i32_a; + short i16_a; + char i8_a; + switch(size){ + case 8: + i8_a = a; + return (i8_a >> b)&0xff; + case 16: + i16_a = a; + return (i16_a >> b)&0xffff; + case 32: + i32_a = a; + return (i32_a >> b)&0xffffffff; + default: + printf("inv size in shift %d\n", size); + exit(0); + } +} +/* +int shift_right_arith_08(int a, unsigned int b) +{ + char i8_a; + i8_a = a; + return (i8_a >> b)&0xff; +} + +int shift_right_arith_16(int a, unsigned int b) +{ + short i16_a; + i16_a = a; + return (i16_a >> b)&0xffff; +} + +int shift_right_arith_32(int a, unsigned int b) +{ + int i32_a; + i32_a = a; + return (i32_a >> b)&0xffffffff; +} +*/ +unsigned int shift_right_logic(unsigned int size, unsigned int a, unsigned int b) +{ + unsigned int u32_a; + unsigned short u16_a; + unsigned char u8_a; + switch(size){ + case 8: + u8_a = a; + return (u8_a >> b)&0xff; + case 16: + u16_a = a; + return (u16_a >> b)&0xffff; + case 32: + u32_a = a; + return (u32_a >> b)&0xffffffff; + default: + printf("inv size in shift %d\n", size); + exit(0); + } +} +/* +int shift_right_logic_08(unsigned int a, unsigned int b) +{ + unsigned char u8_a; + u8_a = a; + return (u8_a >> b)&0xff; +} + +int shift_right_logic_16(unsigned int a, unsigned int b) +{ + unsigned short u16_a; + u16_a = a; + return (u16_a >> b)&0xffff; +} + +int shift_right_logic_32(unsigned int a, unsigned int b) +{ + unsigned int u32_a; + u32_a = a; + return (u32_a >> b)&0xffffffff; +} +*/ +int shift_left_logic(unsigned int size, unsigned int a, unsigned int b) +{ + switch(size){ + case 8: + return (a<<b)&0xff; + case 16: + return (a<<b)&0xffff; + case 32: + return (a<<b)&0xffffffff; + default: + printf("inv size in shift %d\n", size); + exit(0); + } +} +/* +int shift_left_logic_O8(unsigned int a, unsigned int b) +{ + return (a<<b)&0xff; +} + +int shift_left_logic_16(unsigned int a, unsigned int b) +{ + return (a<<b)&0xffff; +} + +int shift_left_logic_32(unsigned int a, unsigned int b) +{ + return (a<<b)&0xffffffff; +} +*/ + +unsigned int mul_lo_op(unsigned int size, unsigned int a, unsigned int b) +{ + unsigned int mask; + + switch (size) { + case 8: mask = 0xff; break; + case 16: mask = 0xffff; break; + case 32: mask = 0xffffffff; break; + default: printf("inv size in mul %d\n", size); exit(0); + } + + a &= mask; + b &= mask; + return ((long long)a * (long long) b) & mask; +} + +unsigned int mul_hi_op(unsigned int size, unsigned int a, unsigned int b) +{ + unsigned long long res = 0; + unsigned int mask; + + switch (size) { + case 8: mask = 0xff; break; + case 16: mask = 0xffff; break; + case 32: mask = 0xffffffff; break; + default: printf("inv size in mul %d\n", size); exit(0); + } + + a &= mask; + b &= mask; + res = ((unsigned long long)a * (unsigned long long)b); + return (res >> 32) & mask; +} + + +unsigned int imul_lo_op_08(char a, char b) +{ + return a*b; +} + +unsigned int imul_lo_op_16(short a, short b) +{ + return a*b; +} + +unsigned int imul_lo_op_32(int a, int b) +{ + return a*b; +} + +int imul_hi_op_08(char a, char b) +{ + long long res = 0; + res = a*b; + return res>>8; +} + +int imul_hi_op_16(short a, short b) +{ + long long res = 0; + res = a*b; + return res>>16; +} + +int imul_hi_op_32(int a, int b) +{ + long long res = 0; + res = a*b; + return res>>32; +} + + + +unsigned int div_op(unsigned int size, unsigned int a, unsigned int b, unsigned int c) +{ + long long int num; + if (c == 0) + { + vmcpu.vm_exception_flags |= EXCEPT_INT_DIV_BY_ZERO; + return 0; + } + num = ((long long)a << size) + b; + num/=(long long)c; + return num; +} + +unsigned int rem_op(unsigned int size, unsigned int a, unsigned int b, unsigned int c) +{ + long long int num; + + if (c == 0) + { + vmcpu.vm_exception_flags |= EXCEPT_INT_DIV_BY_ZERO; + return 0; + } + + num = ((long long )a << size) + b; + num = (long long)num-c*(num/c); + return num; +} + + +int rot_left(unsigned int size, unsigned int a, unsigned int b) +{ + unsigned int tmp; + + b = b&0x1F; + b %= size; + switch(size){ + case 8: + tmp = (a << b) | ((a&0xFF) >> (size-b)); + return tmp&0xff; + case 16: + tmp = (a << b) | ((a&0xFFFF) >> (size-b)); + return tmp&0xffff; + case 32: + tmp = (a << b) | ((a&0xFFFFFFFF) >> (size-b)); + return tmp&0xffffffff; + default: + printf("inv size in rotleft %d\n", size); + exit(0); + } +} + +int rot_right(unsigned int size, unsigned int a, unsigned int b) +{ + unsigned int tmp; + + b = b&0x1F; + b %= size; + switch(size){ + case 8: + tmp = ((a&0xFF) >> b) | (a << (size-b)); + return tmp&0xff; + case 16: + tmp = ((a&0xFFFF) >> b) | (a << (size-b)); + return tmp&0xffff; + case 32: + tmp = ((a&0xFFFFFFFF) >> b) | (a << (size-b)); + return tmp&0xffffffff; + default: + printf("inv size in rotleft %d\n", size); + exit(0); + } +} + + +int rcl_rez_op(unsigned int size, unsigned int a, unsigned int b, unsigned int cf) +{ + unsigned long long tmp; + + tmp = (cf << size) | a; + + size++; + b = b&0x1F; + b %= size; + + switch(size){ + case 8+1: + tmp = (tmp << b) | ((tmp&0x1FF) >> (size-b)); + return tmp&0xff; + case 16+1: + tmp = (tmp << b) | ((tmp&0x1FFFF) >> (size-b)); + return tmp&0xffff; + case 32+1: + tmp = (tmp << b) | ((tmp&0x1FFFFFFFFULL) >> (size-b)); + return tmp&0xffffffff; + default: + printf("inv size in rclleft %d\n", size); + exit(0); + } +} + +int rcr_rez_op(unsigned int size, unsigned int a, unsigned int b, unsigned int cf) +{ + return rcl_rez_op(size, a, size+1-b, cf); + +} + + +int rcl_cf_op(unsigned int size, unsigned int a, unsigned int b, unsigned int cf) +{ + unsigned long long tmp; + + tmp = (cf<< size) | a; + + size++; + b = b&0x1F; + b %= size; + + switch(size){ + case 8+1: + tmp = (tmp << b) | ((tmp&0x1FF) >> (size-b)); + return (tmp>>8)&1; + case 16+1: + tmp = (tmp << b) | ((tmp&0x1FFFF) >> (size-b)); + return (tmp>>16)&1; + case 32+1: + tmp = (tmp << b) | ((tmp&0x1FFFFFFFFULL) >> (size-b)); + return (tmp>>32)&1; + default: + printf("inv size in rclleft %d\n", size); + exit(0); + } +} + +int rcr_cf_op(unsigned int size, unsigned int a, unsigned int b, unsigned int cf) +{ + return rcl_cf_op(size, a, size+1-b, cf); +} +unsigned int my_bsr(unsigned int a, unsigned int b) +{ + int i; + + for (i=31; i>=0; i--){ + if (b & (1<<i)) + return i; + } + return a; +} + +unsigned int my_bsf(unsigned int a, unsigned int b) +{ + int i; + + for (i=0; i<32; i++){ + if (b & (1<<i)) + return i; + } + return a; +} + + +unsigned int my_imul08(unsigned int a, unsigned int b) +{ + char a08, b08; + short a16; + + a08 = a&0xFF; + b08 = b&0xFF; + a16 = a08*b08; + return (int)a16; +} + + + +unsigned int cpuid(unsigned int a, unsigned int reg_num) +{ + if (reg_num >3){ + printf("zarb cpuid reg %x\n", reg_num); + exit(-1); + } + + if (a == 0){ + switch(reg_num){ + case 0: + return 0xa; + case 1: + return 0x756E6547; + case 2: + return 0x6C65746E; + case 3: + return 0x49656E69; + } + } + + else if (a == 1){ + switch(reg_num){ + case 0: + return 0x000006FB; + case 1: + return 0x02040800; + case 2: + return 0x0004E3BD; + case 3: + return 0xBFEBFBFF; + } + } + else{ + printf("WARNING zarb cpuid index %X!\n", a); + //exit(-1); + } + + return 0; +} + + +double mem_32_to_double(unsigned int m) +{ + float f; + double d; + + f = *((float*)&m); + d = f; + return d; +} + + +double mem_64_to_double(unsigned long long m) +{ + double d; + d = *((double*)&m); + return d; +} + +double int_32_to_double(unsigned int m) +{ + double d; + + d = (double)m; + return d; +} + +double int_64_to_double(unsigned long long m) +{ + double d; + + d = (double)m; + return d; +} + +int double_to_int_32(double d) +{ + int i; + + i = (int)d; + return i; +} + +double fadd(double a, double b) +{ + double c; + c = a + b; + return c; +} + + + +unsigned int fcom_c0(double a, double b) +{ + if (a>=b) + return 0; + return 1; +} +unsigned int fcom_c1(double a, double b) +{ + //XXX + return 0; +} +unsigned int fcom_c2(double a, double b) +{ + return 0; +} +unsigned int fcom_c3(double a, double b) +{ + if (a==b) + return 1; + return 0; +} + + +unsigned int double_to_mem_32(double d) +{ + unsigned int m; + float f; + f = d; + m = *((unsigned int*)&f); + return m; +} + +unsigned long long double_to_mem_64(double d) +{ + unsigned long long m; + m = *((unsigned long long*)&d); + return m; +} + +struct memory_page_node * create_memory_page_node(unsigned int ad, unsigned int size, unsigned int access) +{ + struct memory_page_node * mpn; + void* p; + + mpn = malloc(sizeof(*mpn)); + if (!mpn){ + printf("cannot alloc mpn\n"); + exit(-1); + } + + p = malloc(size); + if (!p){ + printf("cannot alloc %d\n", size); + exit(-1); + } + + mpn->ad = ad; + mpn->size = size; + mpn->access = access; + mpn->ad_hp = p; + + return mpn; +} + + +struct code_bloc_node * create_code_bloc_node(unsigned int ad_start, unsigned int ad_stop) +{ + struct code_bloc_node * cbp; + + cbp = malloc(sizeof(*cbp)); + if (!cbp){ + printf("cannot alloc cbp\n"); + exit(-1); + } + + cbp->ad_start = ad_start; + cbp->ad_stop = ad_stop; + + return cbp; +} + + +void add_code_bloc(struct code_bloc_node* cbp) +{ + LIST_INSERT_HEAD(&code_bloc_pool, cbp, next); + if (code_bloc_pool_ad_min> cbp->ad_start) + code_bloc_pool_ad_min = cbp->ad_start; + if (code_bloc_pool_ad_max< cbp->ad_stop) + code_bloc_pool_ad_max = cbp->ad_stop; +} + +void dump_code_bloc_pool(void) +{ + struct code_bloc_node * cbp; + + LIST_FOREACH(cbp, &code_bloc_pool, next){ + printf("ad start %.8X ad_stop %.8X\n", + cbp->ad_start, + cbp->ad_stop); + + } +} + + +void init_memory_page_pool(void) +{ + unsigned int i; + LIST_INIT(&memory_page_pool); + for (i=0;i<MAX_MEMORY_PAGE_POOL_TAB; i++) + memory_page_pool_tab[i] = NULL; + +} + +void init_code_bloc_pool(void) +{ + LIST_INIT(&code_bloc_pool); + code_bloc_pool_ad_min = 0xffffffff; + code_bloc_pool_ad_max = 0; +} + + + +void reset_memory_page_pool(void) +{ + struct memory_page_node * mpn; + unsigned int i; + + while (!LIST_EMPTY(&memory_page_pool)) { + mpn = LIST_FIRST(&memory_page_pool); + LIST_REMOVE(mpn, next); + free(mpn->ad_hp); + free(mpn); + } + for (i=0;i<MAX_MEMORY_PAGE_POOL_TAB; i++) + memory_page_pool_tab[i] = NULL; + +} + + +void reset_code_bloc_pool(void) +{ + struct code_bloc_node * cbp; + + + while (!LIST_EMPTY(&code_bloc_pool)) { + cbp = LIST_FIRST(&code_bloc_pool); + LIST_REMOVE(cbp, next); + free(cbp); + } + code_bloc_pool_ad_min = 0xffffffff; + code_bloc_pool_ad_max = 0; +} + +void insert_mpn_in_tab(struct memory_page_node* mpn_a) +{ + unsigned int i; + for (i=mpn_a->ad >> MEMORY_PAGE_POOL_MASK_BIT;i<(mpn_a->ad + mpn_a->size + PAGE_SIZE - 1)>>MEMORY_PAGE_POOL_MASK_BIT; i++){ + if (memory_page_pool_tab[i] !=NULL){ + printf("known page in tab\n"); + exit(1); + } + memory_page_pool_tab[i] = mpn_a; + } + +} + +void add_memory_page(struct memory_page_node* mpn_a) +{ + struct memory_page_node * mpn; + struct memory_page_node * lmpn; + //unsigned int i; + if (LIST_EMPTY(&memory_page_pool)){ + LIST_INSERT_HEAD(&memory_page_pool, mpn_a, next); + insert_mpn_in_tab(mpn_a); + return; + } + LIST_FOREACH(mpn, &memory_page_pool, next){ + lmpn = mpn; + if (mpn->ad < mpn_a->ad) + continue; + LIST_INSERT_BEFORE(mpn, mpn_a, next); + insert_mpn_in_tab(mpn_a); + return; + + } + LIST_INSERT_AFTER(lmpn, mpn_a, next); + insert_mpn_in_tab(mpn_a); + +} + +void dump_memory_page_pool() +{ + struct memory_page_node * mpn; + + LIST_FOREACH(mpn, &memory_page_pool, next){ + printf("ad %.8X size %.8X %c%c%c hpad %p\n", + mpn->ad, + mpn->size, + mpn->access & PAGE_READ? 'R':'_', + mpn->access & PAGE_WRITE? 'W':'_', + mpn->access & PAGE_EXEC? 'X':'_', + mpn->ad_hp + ); + } + + +} + + + + + + +unsigned int get_memory_page_max_address(void) +{ + struct memory_page_node * mpn; + unsigned int ad = 0; + + LIST_FOREACH(mpn, &memory_page_pool, next){ + if (ad < mpn->ad + mpn->size) + ad = mpn->ad + mpn->size; + } + return ad; +} + +unsigned int get_memory_page_max_user_address(void) +{ + struct memory_page_node * mpn; + unsigned int ad = 0; + + LIST_FOREACH(mpn, &memory_page_pool, next){ + if (ad < mpn->ad + mpn->size && mpn->ad + mpn->size < 0x80000000) + ad = mpn->ad + mpn->size; + } + return ad; +} + + +unsigned int get_memory_page_next(unsigned int n_ad) +{ + struct memory_page_node * mpn; + unsigned int ad = 0; + + LIST_FOREACH(mpn, &memory_page_pool, next){ + if (mpn->ad < n_ad) + continue; + + if (ad == 0 || mpn->ad <ad) + ad = mpn->ad; + } + + return ad; + +} + +unsigned int get_memory_page_from_min_ad(unsigned int size) +{ + struct memory_page_node * mpn; + unsigned int c_ad ; + unsigned int min_ad = min_page_ad; + int end = 0; + /* first, find free min ad */ + while (!end){ + end = 1; + LIST_FOREACH(mpn, &memory_page_pool, next){ + c_ad = (mpn->ad + mpn->size+0x1000)&0xfffff000; + if (c_ad <= min_ad) + continue; + if (mpn->ad <= min_ad){ + min_ad = c_ad; + end = 0; + break; + } + + if (mpn->ad - min_ad < size){ + min_ad = c_ad; + end = 0; + break; + } + } + } + return min_ad; + } + + + + +/********************************************/ + +void hexdump(char* m, unsigned int l) +{ + int i, j, last; + last = 0; + for (i=0;i<l;i++){ + if (!(i%0x10) && i){ + last = i; + printf(" "); + + for (j=-0x10;j<0;j++){ + if (isprint(m[i+j])){ + printf("%c", m[i+j]); + } + else{ + printf("."); + } + } + printf("\n"); + } + printf("%.2X ", m[i]&0xFF); + } + + l-=last; + if (l){ + + for (j=i;j<last+0x10;j++) + printf(" "); + printf(" "); + + for (j = 0;l;j++){ + if (isprint(m[last+j])){ + printf("%c", m[last+j]); + } + else{ + printf("."); + } + l--; + } + } + printf("\n"); + +} + + + + + +void _vm_init_regs() +{ + vmcpu.eax = vmcpu.ebx = vmcpu.ecx = vmcpu.edx = vmcpu.esi = vmcpu.edi = vmcpu.esp = vmcpu.ebp = 0; + vmcpu.zf = vmcpu.nf = vmcpu.pf = vmcpu.of = vmcpu.cf = vmcpu.af = vmcpu.df = 0; + + vmcpu.eax_new = vmcpu.ebx_new = vmcpu.ecx_new = vmcpu.edx_new = vmcpu.esi_new = vmcpu.edi_new = vmcpu.esp_new = vmcpu.ebp_new = 0; + vmcpu.zf_new = vmcpu.nf_new = vmcpu.pf_new = vmcpu.of_new = vmcpu.cf_new = vmcpu.af_new = vmcpu.df_new = 0; + vmcpu.esp = 0; +} + + + +unsigned int _get_memory_page_max_address_py(void) +{ + unsigned int ret; + ret = get_memory_page_max_address(); + return ret; +} + +unsigned int _get_memory_page_max_user_address_py(void) +{ + unsigned int ret; + ret = get_memory_page_max_user_address(); + return ret; +} + +unsigned int _get_memory_page_from_min_ad_py(unsigned int size) +{ + unsigned int ret; + ret = get_memory_page_from_min_ad(size); + return ret; +} + + + + +//#include "libcodenat_interface.c" diff --git a/miasm/tools/emul_lib/libcodenat.h b/miasm/tools/emul_lib/libcodenat.h new file mode 100644 index 00000000..351e6210 --- /dev/null +++ b/miasm/tools/emul_lib/libcodenat.h @@ -0,0 +1,452 @@ +/* +** Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License along +** with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef CODENAT_H +#define CODENAT_H + + +#if __BYTE_ORDER == __BIG_ENDIAN +#define Endian16_Swap(value) \ + ((((uint16_t)((value) & 0x00FF)) << 8) | \ + (((uint16_t)((value) & 0xFF00)) >> 8)) + +#define Endian32_Swap(value) \ + ((((uint32_t)((value) & 0x000000FF)) << 24) | \ + (((uint32_t)((value) & 0x0000FF00)) << 8) | \ + (((uint32_t)((value) & 0x00FF0000)) >> 8) | \ + (((uint32_t)((value) & 0xFF000000)) >> 24)) + +#define Endian64_Swap(value) \ + (((((uint64_t)value)<<56) & 0xFF00000000000000ULL) | \ + ((((uint64_t)value)<<40) & 0x00FF000000000000ULL) | \ + ((((uint64_t)value)<<24) & 0x0000FF0000000000ULL) | \ + ((((uint64_t)value)<< 8) & 0x000000FF00000000ULL) | \ + ((((uint64_t)value)>> 8) & 0x00000000FF000000ULL) | \ + ((((uint64_t)value)>>24) & 0x0000000000FF0000ULL) | \ + ((((uint64_t)value)>>40) & 0x000000000000FF00ULL) | \ + ((((uint64_t)value)>>56) & 0x00000000000000FFULL)) +#else +#define Endian16_Swap(value) (value) + +#define Endian32_Swap(value) (value) + +#define Endian64_Swap(value) (value) +#endif + + + + +LIST_HEAD(memory_page_list_head, memory_page_node); +LIST_HEAD(code_bloc_list_head, code_bloc_node); + + +typedef struct { + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; + unsigned int esi; + unsigned int edi; + unsigned int esp; + unsigned int ebp; + unsigned int eip; + + unsigned int zf; + unsigned int nf; + unsigned int pf; + unsigned int of; + unsigned int cf; + unsigned int af; + unsigned int df; + + unsigned int eax_new; + unsigned int ebx_new; + unsigned int ecx_new; + unsigned int edx_new; + unsigned int esi_new; + unsigned int edi_new; + unsigned int esp_new; + unsigned int ebp_new; + unsigned int eip_new; + + unsigned int zf_new; + unsigned int nf_new; + unsigned int pf_new; + unsigned int of_new; + unsigned int cf_new; + unsigned int af_new; + unsigned int df_new; + + unsigned int tf; + unsigned int i_f; + unsigned int iopl_f; + unsigned int nt; + unsigned int rf; + unsigned int vm; + unsigned int ac; + unsigned int vif; + unsigned int vip; + unsigned int i_d; + unsigned int tf_new; + unsigned int i_f_new; + unsigned int iopl_f_new; + unsigned int nt_new; + unsigned int rf_new; + unsigned int vm_new; + unsigned int ac_new; + unsigned int vif_new; + unsigned int vip_new; + unsigned int i_d_new; + + unsigned int my_tick; + + + + unsigned int cond; + + unsigned int ds; + + unsigned int vm_exception_flags; + unsigned int vm_exception_flags_new; + + unsigned int vm_last_write_ad; + unsigned int vm_last_write_size ; + + + + double float_st0; + double float_st1; + double float_st2; + double float_st3; + double float_st4; + double float_st5; + double float_st6; + double float_st7; + + double float_st0_new; + double float_st1_new; + double float_st2_new; + double float_st3_new; + double float_st4_new; + double float_st5_new; + double float_st6_new; + double float_st7_new; + + unsigned int float_c0; + unsigned int float_c1; + unsigned int float_c2; + unsigned int float_c3; + + unsigned int float_c0_new; + unsigned int float_c1_new; + unsigned int float_c2_new; + unsigned int float_c3_new; + + + unsigned int float_stack_ptr; + unsigned int float_stack_ptr_new; + + unsigned int reg_float_control; + unsigned int reg_float_control_new; + + + unsigned int tsc1; + unsigned int tsc2; + + unsigned int cr0; + unsigned int cr0_new; + + unsigned int cr3; + unsigned int cr3_new; + + + //PyObject* known_blocs; + + +}vm_cpu_t; + + +extern vm_cpu_t vmcpu; + +/* +extern unsigned int eax, ebx, ecx, edx, esi, edi, esp, ebp, eip; +extern unsigned int zf, nf, pf, of, cf, af, df; + +extern unsigned int eax_new, ebx_new, ecx_new, edx_new, esi_new, edi_new, esp_new, ebp_new, eip_new; +extern unsigned int zf_new, nf_new, pf_new, of_new, cf_new, af_new, df_new; +extern unsigned int tf, i_f, iopl_f, nt, rf, vm, ac, vif, vip, i_d; +extern unsigned int tf_new, i_f_new, iopl_f_new, nt_new, rf_new, vm_new, ac_new, vif_new, vip_new, i_d_new; + +extern unsigned int my_tick; + +extern unsigned int reg_float_control; + + +extern unsigned int cond; + +extern unsigned int ds; + +extern unsigned int vm_exception_flags; +extern unsigned int vm_exception_flags_new; + +extern unsigned int vm_last_write_ad; +extern unsigned int vm_last_write_size ; +*/ + +typedef struct _memory_page{ +}memory_page; + +struct memory_page_node { + unsigned int ad; + unsigned int size; + unsigned int access; + void* ad_hp; + + //memory_page *mp; + LIST_ENTRY(memory_page_node) next; +}; + + + +struct code_bloc_node { + unsigned int ad_start; + unsigned int ad_stop; + unsigned int ad_code; + LIST_ENTRY(code_bloc_node) next; +}; + + +#define PAGE_READ 1 +#define PAGE_WRITE 2 +#define PAGE_EXEC 4 + + +//memory_page* create_memory_page(unsigned int ad, unsigned int size); + +//PyObject* _vm_get_exception(unsigned int xcpt); + +// interrupt with eip update after instr +#define EXCEPT_CODE_AUTOMOD (1<<0) +#define EXCEPT_SOFT_BP (1<<1) + +#define EXCEPT_NUM_UDPT_EIP (1<<1) + +// interrupt with eip at instr +#define EXCEPT_UNK_MEM_AD (1<<2) +#define EXCEPT_THROW_SEH (1<<3) +#define EXCEPT_UNK_EIP (1<<4) +#define EXCEPT_ACCESS_VIOL (1<<5) +#define EXCEPT_INT_DIV_BY_ZERO (1<<6) +#define EXCEPT_PRIV_INSN (1<<7) +#define EXCEPT_ILLEGAL_INSN (1<<8) + +void dump_gpregs(void); +void MEM_WRITE(unsigned int my_size, unsigned int addr , unsigned int src); +unsigned int MEM_LOOKUP(unsigned int my_size, unsigned int addr); + + +void MEM_WRITE_08(unsigned int addr , unsigned char src); +void MEM_WRITE_16(unsigned int addr , unsigned short src); +void MEM_WRITE_32(unsigned int addr , unsigned int src); +void MEM_WRITE_64(unsigned int addr , unsigned long long src); + + +unsigned char MEM_LOOKUP_08(unsigned int addr); +unsigned short MEM_LOOKUP_16(unsigned int addr); +unsigned int MEM_LOOKUP_32(unsigned int addr); +unsigned long long MEM_LOOKUP_64(unsigned int addr); + + + + +void MEM_WRITE_08_PASSTHROUGH(unsigned int addr, unsigned char src); +void MEM_WRITE_16_PASSTHROUGH(unsigned int addr, unsigned short src); +void MEM_WRITE_32_PASSTHROUGH(unsigned int addr, unsigned int src); +void MEM_WRITE_64_PASSTHROUGH(unsigned int addr, unsigned long long src); +unsigned char MEM_LOOKUP_08_PASSTHROUGH(unsigned int addr); +unsigned short MEM_LOOKUP_16_PASSTHROUGH(unsigned int addr); +unsigned int MEM_LOOKUP_32_PASSTHROUGH(unsigned int addr); +unsigned long long MEM_LOOKUP_64_PASSTHROUGH(unsigned int addr); + + +inline unsigned int parity(unsigned int a); +unsigned int my_imul08(unsigned int a, unsigned int b); + +void vm_throw(unsigned long flags); +int shift_right_arith(unsigned int size, int a, unsigned int b); +unsigned int shift_right_logic(unsigned int size, unsigned int a, unsigned int b); +int shift_left_logic(unsigned int size, unsigned int a, unsigned int b); +/* +int shift_left_logic_08(unsigned int a, unsigned int b); +int shift_left_logic_16(unsigned int a, unsigned int b); +int shift_left_logic_32(unsigned int a, unsigned int b); +*/ +unsigned int mul_lo_op(unsigned int size, unsigned int a, unsigned int b); +unsigned int mul_hi_op(unsigned int size, unsigned int a, unsigned int b); +unsigned int imul_lo_op_08(char a, char b); +unsigned int imul_lo_op_16(short a, short b); +unsigned int imul_lo_op_32(int a, int b); +int imul_hi_op_08(char a, char b); +int imul_hi_op_16(short a, short b); +int imul_hi_op_32(int a, int b); + + +unsigned int div_op(unsigned int size, unsigned int a, unsigned int b, unsigned int c); +unsigned int rem_op(unsigned int size, unsigned int a, unsigned int b, unsigned int c); +int rot_left(unsigned int size, unsigned int a, unsigned int b); +int rot_right(unsigned int size, unsigned int a, unsigned int b); +int rcl_rez_op(unsigned int size, unsigned int a, unsigned int b, unsigned int cf); +int rcl_cf_op(unsigned int size, unsigned int a, unsigned int b, unsigned int cf); +void _vm_init_regs(void); + + +//PyObject* _vm_push_uint32_t(PyObject *item); +//PyObject* _vm_pop_uint32_t(void); +////PyObject* _vm_put_str(PyObject *item); +//PyObject* _vm_set_mem(PyObject *item, PyObject *item_str); +//PyObject* _vm_set_mem_access(PyObject *addr, PyObject *access); +//PyObject* _vm_get_str(PyObject *item, PyObject *item_len); +//PyObject* _vm_add_memory_page(PyObject *item, PyObject *access, PyObject *item_str); +//PyObject* _vm_add_code_bloc(PyObject *item1, PyObject *item2);//, PyObject *item3); +//PyObject* _call_pyfunc_from_globals(char* funcname); +//PyObject* _call_pyfunc_from_eip(void); +// +//PyObject* call_pyfunc_from_globals(char* funcname); +// +//PyObject* _vm_get_gpreg(void); + +typedef struct _reg_dict{ + char* name; + unsigned int* ptr; +} reg_dict; + +extern reg_dict gpreg_dict[]; +//PyObject* _vm_set_gpreg(PyObject *dict); + + +void hexdump(char* m, unsigned int l); + +struct code_bloc_node * create_code_bloc_node(unsigned int ad_start, unsigned int ad_stop); +void add_code_bloc(struct code_bloc_node* cbp); + +struct memory_page_node * create_memory_page_node(unsigned int ad, unsigned int size, unsigned int access);//memory_page* mp); +void init_memory_page_pool(void); +void init_code_bloc_pool(void); +void reset_memory_page_pool(void); +void reset_code_bloc_pool(void); +void dump_code_bloc_pool(void); + + + +void add_memory_page(struct memory_page_node* mpn); + +void dump_memory_page_pool(void); +//PyObject* _vm_get_all_memory(void); + + + + +/********************************************/ + +//PyObject* _vm_get_cpu_state(void); +//PyObject* _vm_set_cpu_state(PyObject * s_cpustate); + + +//void memory_page_write(unsigned int my_size, unsigned int ad, unsigned int src); +//unsigned int memory_page_read(unsigned int my_size, unsigned int ad); +unsigned int get_memory_page_max_address(void); +unsigned int get_memory_page_max_user_address(void); + + + + +void _func_free(void); +void _func_alloc(void); +unsigned int _get_memory_page_max_address_py(void); +unsigned int _get_memory_page_max_user_address_py(void); +unsigned int _get_memory_page_from_min_ad_py(unsigned int size); + +void _func_malloc_memory_page(void); +void _func_free_memory_page(void); +void _func_virtualalloc_memory_page(void); +void _func_virtualfree_memory_page(void); +void _func_loadlib_fake(void); +void _func_getproc_fake(void); + + +void func_free(void); +void func_alloc(void); +unsigned int get_memory_page_max_address_py(void); +unsigned int get_memory_page_max_user_address_py(void); +unsigned int get_memory_page_from_min_ad_py(unsigned int size); +struct memory_page_node * get_memory_page_from_address(unsigned int ad); +void func_malloc_memory_page(void); +void func_free_memory_page(void); +void func_virtualalloc_memory_page(void); +void func_virtualfree_memory_page(void); +void func_loadlib_fake(void); +void func_getproc_fake(void); + + +//PyObject* _vm_exec_bloc(PyObject* my_eip, PyObject* known_blocs); + +unsigned int cpuid(unsigned int a, unsigned int reg_num); +double int2double(unsigned int m); +//PyObject* _vm_exec_blocs(PyObject* my_eip); + +double fadd(double a, double b); +unsigned int fcom_c0(double a, double b); +unsigned int fcom_c1(double a, double b); +unsigned int fcom_c2(double a, double b); +unsigned int fcom_c3(double a, double b); + + + +double mem_32_to_double(unsigned int m); +double mem_64_to_double(unsigned long long m); +double int_32_to_double(unsigned int m); +double int_64_to_double(unsigned long long m); +int double_to_int_32(double d); +double fadd(double a, double b); +unsigned int double_to_mem_32(double d); +unsigned long long double_to_mem_64(double d); + + +#define shift_right_arith_08(a, b)\ + ((((char)(a)) >> ((unsigned int)(b)))&0xff) +#define shift_right_arith_16(a, b)\ + ((((short)(a)) >> ((unsigned int)(b)))&0xffff) +#define shift_right_arith_32(a, b)\ + ((((int)(a)) >> ((unsigned int)(b)))&0xffffffff) + + +#define shift_right_logic_08(a, b)\ + ((((unsigned char)(a)) >> ((unsigned int)(b)))&0xff) +#define shift_right_logic_16(a, b)\ + ((((unsigned short)(a)) >> ((unsigned int)(b)))&0xffff) +#define shift_right_logic_32(a, b)\ + ((((unsigned int)(a)) >> ((unsigned int)(b)))&0xffffffff) + + +#define shift_left_logic_08(a, b)\ + (((a)<<(b))&0xff) +#define shift_left_logic_16(a, b)\ + (((a)<<(b))&0xffff) +#define shift_left_logic_32(a, b)\ + (((a)<<(b))&0xffffffff) + +#endif diff --git a/miasm/tools/emul_lib/libcodenat_interface.c b/miasm/tools/emul_lib/libcodenat_interface.c new file mode 100644 index 00000000..c94295b2 --- /dev/null +++ b/miasm/tools/emul_lib/libcodenat_interface.c @@ -0,0 +1,1108 @@ +/* +** Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License along +** with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <Python.h> +#include "queue.h" +#include "libcodenat.h" + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +extern struct memory_page_list_head memory_page_pool; +extern struct code_bloc_list_head code_bloc_pool; + +#define RAISE(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return p;} + +PyObject* _vm_get_exception(unsigned int xcpt) +{ + PyObject*p; + + if (!xcpt) + p = NULL; + else if (xcpt & EXCEPT_CODE_AUTOMOD) + p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_CODE_AUTOMOD" ); + else if (xcpt & EXCEPT_UNK_EIP) + p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_UNK_EIP" ); + else if (xcpt & EXCEPT_UNK_MEM_AD) + p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_UNK_MEM_AD" ); + + else p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_UNKNOWN" ); + + return p; +} + +PyObject* _vm_get_all_memory(void) +{ + struct memory_page_node * mpn; + PyObject *dict; + PyObject *dict2; + + PyObject *o; + + dict = PyDict_New(); + + LIST_FOREACH(mpn, &memory_page_pool, next){ + /* + printf("ad %.8X size %.8X %c%c%c hpad %p\n", + mpn->ad, + mpn->size, + mpn->access & PAGE_READ? 'R':'_', + mpn->access & PAGE_WRITE? 'W':'_', + mpn->access & PAGE_EXEC? 'X':'_', + mpn->ad_hp + ); + */ + + dict2 = PyDict_New(); + + o = PyString_FromStringAndSize(mpn->ad_hp, mpn->size); + PyDict_SetItemString(dict2, "data", o); + Py_DECREF(o); + + o = PyInt_FromLong((long)mpn->size); + PyDict_SetItemString(dict2, "size", o); + Py_DECREF(o); + + o = PyInt_FromLong((long)mpn->access); + PyDict_SetItemString(dict2, "access", o); + Py_DECREF(o); + + o = PyInt_FromLong((long)mpn->ad); + PyDict_SetItem(dict, o, dict2); + Py_DECREF(o); + Py_DECREF(dict2); + } + return dict; +} + + +PyObject* _vm_get_gpreg(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + o = PyInt_FromLong((long)vmcpu.eax); + PyDict_SetItemString(dict, "eax", o); + Py_DECREF(o); + o = PyInt_FromLong((long)vmcpu.ebx); + PyDict_SetItemString(dict, "ebx", o); + Py_DECREF(o); + o = PyInt_FromLong((long)vmcpu.ecx); + PyDict_SetItemString(dict, "ecx", o); + Py_DECREF(o); + o = PyInt_FromLong((long)vmcpu.edx); + PyDict_SetItemString(dict, "edx", o); + Py_DECREF(o); + o = PyInt_FromLong((long)vmcpu.esi); + PyDict_SetItemString(dict, "esi", o); + Py_DECREF(o); + o = PyInt_FromLong((long)vmcpu.edi); + PyDict_SetItemString(dict, "edi", o); + Py_DECREF(o); + o = PyInt_FromLong((long)vmcpu.esp); + PyDict_SetItemString(dict, "esp", o); + Py_DECREF(o); + o = PyInt_FromLong((long)vmcpu.ebp); + PyDict_SetItemString(dict, "ebp", o); + Py_DECREF(o); + o = PyInt_FromLong((long)vmcpu.eip); + PyDict_SetItemString(dict, "eip", o); + Py_DECREF(o); + + + return dict; + + +} + +reg_dict gpreg_dict[] = { {.name = "eax", .ptr = &(vmcpu.eax)}, + {.name = "ebx", .ptr = &(vmcpu.ebx)}, + {.name = "ecx", .ptr = &(vmcpu.ecx)}, + {.name = "edx", .ptr = &(vmcpu.edx)}, + {.name = "esi", .ptr = &(vmcpu.esi)}, + {.name = "edi", .ptr = &(vmcpu.edi)}, + {.name = "esp", .ptr = &(vmcpu.esp)}, + {.name = "ebp", .ptr = &(vmcpu.ebp)}, + {.name = "eip", .ptr = &(vmcpu.eip)}, +}; + +PyObject* _vm_set_gpreg(PyObject *dict) +{ + PyObject *d_key, *d_value = NULL; + int pos = 0; + unsigned int val; + unsigned int i, found; + + + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + + while(PyDict_Next(dict, &pos, &d_key, &d_value)){ + if(!PyString_Check(d_key)) + RAISE(PyExc_TypeError, "key must be str"); + + + if (PyInt_Check(d_value)){ + val = (unsigned int)PyInt_AsLong(d_value); + } + else if (PyLong_Check(d_value)){ + val = (unsigned int)PyInt_AsUnsignedLongLongMask(d_value); + } + else{ + RAISE(PyExc_TypeError,"value must be int"); + } + + + found = 0; + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(PyString_AsString(d_key), gpreg_dict[i].name)) + continue; + *(gpreg_dict[i].ptr) = val; + found = 1; + break; + } + + if (found) + continue; + + printf("unkown key: %s\n", PyString_AsString(d_key)); + + RAISE(PyExc_ValueError, "unkown reg"); + } + return NULL; +} + + +PyObject* _vm_add_memory_page(PyObject *item, PyObject *access, PyObject *item_str) +{ + unsigned int buf_size; + char* buf_data; + //char* buf_data_aligned; + Py_ssize_t length; + int ret = 0x1337beef; + unsigned int page_addr; + unsigned int page_access; + + struct memory_page_node * mpn; + + if (PyInt_Check(item)){ + page_addr = (unsigned int)PyInt_AsLong(item); + } + else if (PyLong_Check(item)){ + page_addr = (unsigned int)PyInt_AsUnsignedLongLongMask(item); + } + else{ + RAISE(PyExc_TypeError,"arg1 must be int"); + } + + + + if (PyInt_Check(access)){ + page_access = (unsigned int)PyInt_AsLong(access); + } + else if (PyLong_Check(item)){ + page_access = (unsigned int)PyInt_AsUnsignedLongLongMask(access); + } + else{ + RAISE(PyExc_TypeError,"arg2 must be int"); + } + + + + //printf("add page: %X\n", page_addr); + + if(!PyString_Check(item_str)) + RAISE(PyExc_TypeError,"arg must be str"); + + buf_size = PyString_Size(item_str); + //printf("add page %X size: %X\n", page_addr, buf_size); + + PyString_AsStringAndSize(item_str, &buf_data, &length); + + + mpn = create_memory_page_node(page_addr, buf_size, page_access); + memcpy(mpn->ad_hp, buf_data, buf_size); + add_memory_page(mpn); + + return PyInt_FromLong((long)ret); +} + +PyObject* _call_pyfunc_from_globals(char* funcname) +{ + PyObject *mod, *func, *rslt, *globals, *func_globals; + + printf("getting pyfunc %s\n", funcname); + + mod = PyEval_GetBuiltins(); + + if (!mod) { + printf("cannot find module\n"); + exit(0); + } + + func_globals = PyDict_GetItemString(mod, "globals"); + if (!func_globals) { + printf("cannot find function globals\n"); + exit(0); + } + + if (!PyCallable_Check (func_globals)) { + printf("function not callable\n"); + exit(0); + } + + globals = PyObject_CallObject (func_globals, NULL); + if (!globals) { + printf("cannot get globals\n"); + exit(0); + } + + //Py_XDECREF(func_globals); + //Py_XDECREF(mod); + + + func = PyDict_GetItemString (globals, funcname); + if (!func) { + printf("cannot find function %s\n", funcname); + exit(0); + } + + if (!PyCallable_Check (func)) { + printf("function not callable\n"); + exit(0); + } + + rslt = PyObject_CallObject (func, NULL); + + + return rslt; +} + + + +PyObject* _call_pyfunc_from_eip(void) +{ + PyObject *mod, *func, *rslt, *globals, *func_globals; + char funcname[0x100]; + + printf("getting pybloc %X\n", vmcpu.eip); + sprintf(funcname, "bloc_%.8X", vmcpu.eip); + printf("bloc name %s\n", funcname); + + mod = PyEval_GetBuiltins(); + + if (!mod) { + printf("cannot find module\n"); + exit(0); + } + + func_globals = PyDict_GetItemString(mod, "globals"); + if (!func_globals) { + printf("cannot find function globals\n"); + exit(0); + } + + if (!PyCallable_Check (func_globals)) { + printf("function not callable\n"); + exit(0); + } + + globals = PyObject_CallObject (func_globals, NULL); + if (!globals) { + printf("cannot get globals\n"); + exit(0); + } + + //Py_XDECREF(func_globals); + //Py_XDECREF(mod); + + + func = PyDict_GetItemString (globals, funcname); + if (!func) { + printf("cannot find function %s\n", funcname); + exit(0); + } + + if (!PyCallable_Check (func)) { + printf("function not callable\n"); + exit(0); + } + + rslt = PyObject_CallObject (func, NULL); + + + return rslt; +} + + + + +PyObject* _vm_get_cpu_state(void) +{ + PyObject * o; + o = PyString_FromStringAndSize((char*)&vmcpu, sizeof(vmcpu)); + return o; + +} + + +PyObject* _vm_set_cpu_state(PyObject * s_cpustate) +{ + unsigned int buf_size; + Py_ssize_t length; + char* buf; + + if(!PyString_Check(s_cpustate)) + RAISE(PyExc_TypeError,"arg must be str"); + + buf_size = PyString_Size(s_cpustate); + if (buf_size != sizeof(vmcpu)) + RAISE(PyExc_TypeError,"bad str len"); + + + PyString_AsStringAndSize(s_cpustate, (char**)&buf, &length); + memcpy(&vmcpu, buf, length); + return PyInt_FromLong((long)0); + +} + + +PyObject* _vm_push_uint32_t(int val) +{ + vmcpu.esp-=4; + MEM_WRITE(32, vmcpu.esp, val); + + return PyInt_FromLong((long)vmcpu.esp); +} + + +PyObject* _vm_pop_uint32_t(void) +{ + unsigned int val; + + val = MEM_LOOKUP(32, vmcpu.esp); + vmcpu.esp+=4; + + return PyInt_FromLong((long)val);; +} + +PyObject* _vm_set_mem(PyObject *addr, PyObject *item_str) +{ + unsigned int buf_size; + char* buf_data; + //char* buf_data_aligned; + Py_ssize_t length; + int ret = 0x1337; + unsigned int val; + + struct memory_page_node * mpn; + + if (PyInt_Check(addr)){ + val = (unsigned int)PyInt_AsLong(addr); + } + else if (PyLong_Check(addr)){ + val = (unsigned int)PyInt_AsUnsignedLongLongMask(addr); + } + else{ + RAISE(PyExc_TypeError,"arg1 must be int"); + } + + printf("set addr: %X\n", val); + + if(!PyString_Check(item_str)) + RAISE(PyExc_TypeError,"arg must be str"); + + buf_size = PyString_Size(item_str); + //printf("buf size: %X\n", buf_size); + + PyString_AsStringAndSize(item_str, &buf_data, &length); + + mpn = get_memory_page_from_address(val); + //memcpy((void*)val, buf_data, buf_size); + memcpy(mpn->ad_hp + (val-mpn->ad), buf_data, buf_size); + + return PyInt_FromLong((long)ret); +} + + +PyObject* _vm_set_mem_access(PyObject *addr, PyObject *access) +{ + int ret = 0x1337beef; + unsigned int page_addr; + unsigned int page_access; + + struct memory_page_node * mpn; + + if (PyInt_Check(addr)){ + page_addr = (unsigned int)PyInt_AsLong(addr); + } + else if (PyLong_Check(addr)){ + page_addr = (unsigned int)PyInt_AsUnsignedLongLongMask(addr); + } + else{ + RAISE(PyExc_TypeError,"arg1 must be int"); + } + + if (PyInt_Check(access)){ + page_access = (unsigned int)PyInt_AsLong(access); + } + else if (PyLong_Check(access)){ + page_access = (unsigned int)PyInt_AsUnsignedLongLongMask(access); + } + else{ + RAISE(PyExc_TypeError,"arg2 must be int"); + } + + mpn = get_memory_page_from_address(page_addr); + mpn->access = page_access; + return PyInt_FromLong((long)ret); +} + + +PyObject* _vm_get_str(PyObject *addr, PyObject *item_len) +{ + //unsigned int buf_size; + //char* buf_data; + //char* buf_data_aligned; + //Py_ssize_t length; + //int ret; + unsigned int buf_addr; + unsigned int buf_len; + PyObject *obj_out; + struct memory_page_node * mpn; + char* buf_out; + char * addr_tmp; + char* addr_out; + int off; + unsigned int l; + unsigned int my_size; + + if (PyInt_Check(addr)){ + buf_addr = (unsigned int)PyInt_AsLong(addr); + } + else if (PyLong_Check(addr)){ + buf_addr = (unsigned int)PyInt_AsUnsignedLongLongMask(addr); + } + else{ + RAISE(PyExc_TypeError,"arg1 must be int"); + } + + if (PyInt_Check(item_len)){ + buf_len = (unsigned int)PyInt_AsLong(item_len); + } + else if (PyLong_Check(item_len)){ + buf_len = (unsigned int)PyInt_AsUnsignedLongLongMask(item_len); + } + else{ + RAISE(PyExc_TypeError,"arg must be int"); + } + + my_size = buf_len; + + buf_out = malloc(buf_len); + if (!buf_out){ + printf("cannot alloc read\n"); + exit(-1); + } + + addr_out = buf_out; + + + + + /* read is multiple page wide */ + while (my_size){ + mpn = get_memory_page_from_address(buf_addr); + if (!mpn){ + printf("cannot find page off %X\n", buf_addr); + return 0; + } + + + off = buf_addr - mpn->ad; + addr_tmp = &((char*)mpn->ad_hp)[off]; + + l = MIN(my_size, mpn->size - off); + memcpy(addr_out, addr_tmp, l); + my_size -= l; + addr_out +=l; + buf_addr +=l; + } + + obj_out = PyString_FromStringAndSize(buf_out, buf_len); + free(buf_out); + return obj_out; +} + +PyObject * dump_gpregs_py(PyObject* self, PyObject* args) +{ + dump_gpregs(); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_get_last_write_ad(PyObject* self, PyObject* args) +{ + return PyInt_FromLong((long)vmcpu.vm_last_write_ad); +} + +PyObject* vm_get_last_write_size(PyObject* self, PyObject* args) +{ + return PyInt_FromLong((long)vmcpu.vm_last_write_size); +} + + +PyObject* vm_reset_exception(PyObject* self, PyObject* args) +{ + vmcpu.vm_exception_flags = 0; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_get_exception(PyObject* self, PyObject* args) +{ + return PyInt_FromLong((long)vmcpu.vm_exception_flags); +} + +PyObject * vm_init_regs(PyObject* self, PyObject* args) +{ + _vm_init_regs(); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_push_uint32_t(PyObject* self, PyObject *args) +{ + PyObject* p; + int item; + if (!PyArg_ParseTuple(args, "I", &item)) + return NULL; + p = _vm_push_uint32_t(item); + return p; +} + + +PyObject* vm_pop_uint32_t(PyObject* self, PyObject* args) +{ + PyObject* p; + p = _vm_pop_uint32_t(); + return p; +} + +/* +PyObject* vm_put_str(PyObject *item) +{ + PyObject* p; + p = _vm_put_str(item); + return p; +} +*/ + +PyObject* vm_set_mem(PyObject* self, PyObject* args) +{ + PyObject* p; + PyObject *addr; + PyObject *item_str; + if (!PyArg_ParseTuple(args, "OO", &addr, &item_str)) + return NULL; + + p = _vm_set_mem(addr, item_str); + return p; +} + +PyObject* vm_set_mem_access(PyObject* self, PyObject* args) +{ + PyObject* p; + PyObject *addr; + PyObject *access; + if (!PyArg_ParseTuple(args, "OO", &addr, &access)) + return NULL; + + p = _vm_set_mem_access(addr, access); + return p; +} + + +PyObject* vm_get_str(PyObject* self, PyObject* args) +{ + PyObject* p; + PyObject *item; + PyObject *item_len; + if (!PyArg_ParseTuple(args, "OO", &item, &item_len)) + return NULL; + + p = _vm_get_str(item, item_len); + return p; +} + + +PyObject* vm_get_gpreg(PyObject* self, PyObject* args) +{ + PyObject* p; + p = _vm_get_gpreg(); + return p; +} + +PyObject* vm_set_gpreg(PyObject *self, PyObject *args) +{ + PyObject* dict; + if (!PyArg_ParseTuple(args, "O", &dict)) + return NULL; + _vm_set_gpreg(dict); + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* init_memory_page_pool_py(PyObject* self, PyObject* args) +{ + init_memory_page_pool(); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* init_code_bloc_pool_py(PyObject* self, PyObject* args) +{ + init_code_bloc_pool(); + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* vm_add_memory_page(PyObject* self, PyObject* args) +{ + PyObject *item; + PyObject *access; + PyObject *item_str; + PyObject* p; + if (!PyArg_ParseTuple(args, "OOO", &item, &access, &item_str)) + return NULL; + p = _vm_add_memory_page(item, access, item_str); + return p; +} + + + +PyObject* dump_memory_page_pool_py(PyObject* self, PyObject* args) +{ + dump_memory_page_pool(); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_get_all_memory(PyObject* self, PyObject* args) +{ + PyObject *o; + o = _vm_get_all_memory(); + return o; +} + + +PyObject* reset_memory_page_pool_py(PyObject* self, PyObject* args) +{ + reset_memory_page_pool(); + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* reset_code_bloc_pool_py(PyObject* self, PyObject* args) +{ + reset_code_bloc_pool(); + Py_INCREF(Py_None); + return Py_None; + +} + + +PyObject* call_pyfunc_from_globals(PyObject* self, PyObject* args) +{ + PyObject* p; + char* funcname; + if (!PyArg_ParseTuple(args, "s", &funcname)) + return NULL; + + p = _call_pyfunc_from_globals(funcname); + return p; +} + + +PyObject* _vm_add_code_bloc(PyObject* self, PyObject* args) +{ + PyObject *item1; + PyObject *item2; + int ret = 0x1337beef; + unsigned int ad_start, ad_stop, ad_code = 0; + + struct code_bloc_node * cbp; + + if (!PyArg_ParseTuple(args, "OO", &item1, &item2)) + return NULL; + + + if (PyInt_Check(item1)){ + ad_start = (unsigned int)PyInt_AsLong(item1); + } + else if (PyLong_Check(item1)){ + ad_start = (unsigned int)PyInt_AsUnsignedLongLongMask(item1); + } + else{ + RAISE(PyExc_TypeError,"arg1 must be int"); + } + + + + if (PyInt_Check(item2)){ + ad_stop = (unsigned int)PyInt_AsLong(item2); + } + else if (PyLong_Check(item2)){ + ad_stop = (unsigned int)PyInt_AsUnsignedLongLongMask(item2); + } + else{ + RAISE(PyExc_TypeError,"arg2 must be int"); + } + /* + if (PyInt_Check(item3)){ + ad_code = (unsigned int)PyInt_AsLong(item3); + } + else if (PyLong_Check(item3)){ + ad_code = (unsigned int)PyInt_AsUnsignedLongLongMask(item3); + } + else{ + RAISE(PyExc_TypeError,"arg3 must be int"); + } + */ + + //printf("add code bloc %X %X\n", ad_start, ad_stop); + + + cbp = create_code_bloc_node(ad_start, ad_stop); + cbp->ad_start = ad_start; + cbp->ad_stop = ad_stop; + cbp->ad_code = ad_code; + + + add_code_bloc(cbp); + + return PyInt_FromLong((long)ret); +} + + +PyObject* vm_add_code_bloc(PyObject *item1, PyObject *item2)//, PyObject *item3) +{ + PyObject* p; + p = _vm_add_code_bloc(item1, item2);//, item3); + return p; +} + +PyObject* dump_code_bloc_pool_py(void) +{ + dump_code_bloc_pool(); + Py_INCREF(Py_None); + return Py_None; + +} + + + +PyObject* vm_get_cpu_state(void) +{ + PyObject* o; + o = _vm_get_cpu_state(); + return o; +} + +PyObject* vm_set_cpu_state(PyObject * s_cpustate) +{ + PyObject *o; + o = _vm_set_cpu_state(s_cpustate); + return o; + +} + + + +unsigned int get_memory_page_max_address_py(void) +{ + unsigned int ret; + ret = _get_memory_page_max_address_py(); + return ret; +} + +PyObject * vm_get_memory_page_max_address(PyObject* self, PyObject* args) +{ + PyObject* v; + unsigned int tmp; + + tmp = get_memory_page_max_address_py(); + v = PyInt_FromLong((long)tmp); + return v; +} + +unsigned int get_memory_page_max_user_address_py(void) +{ + unsigned int ret; + ret = _get_memory_page_max_user_address_py(); + return ret; +} + + +unsigned int get_memory_page_from_min_ad_py(unsigned int size) +{ + unsigned int ret; + ret = _get_memory_page_from_min_ad_py(size); + return ret; + +} + + +PyObject* _vm_exec_blocs(PyObject* self, PyObject* args) +{ + PyObject* b; + PyObject* module; + PyObject* func; + PyObject* meip; + unsigned int tmp; + + PyObject* my_eip; + PyObject* known_blocs; + PyObject* e; + + if (!PyArg_ParseTuple(args, "OO", &my_eip, &known_blocs)) + return NULL; + + if(!PyDict_Check(known_blocs)) + RAISE(PyExc_TypeError, "arg must be dict"); + + if (PyInt_Check(my_eip)){ + tmp = (unsigned int)PyInt_AsLong(my_eip); + } + else if (PyLong_Check(my_eip)){ + tmp = (unsigned int)PyInt_AsUnsignedLongLongMask(my_eip); + } + else{ + RAISE(PyExc_TypeError,"arg1 must be int"); + } + + meip = PyInt_FromLong((long)tmp); + while (1){ + b = PyDict_GetItem(known_blocs, meip); + if (b == NULL) + return meip; + module = PyObject_GetAttrString(b, "module_c"); + if (module == NULL) + return meip; + //Py_DECREF(b); + + func = PyObject_GetAttrString(module, "func"); + if (func == NULL) + return meip; + + Py_DECREF(module); + + + if (!PyCallable_Check (func)) { + printf("function not callable\n"); + exit(0); + } + Py_DECREF(meip); + meip = PyObject_CallObject (func, NULL); + + Py_DECREF(func); + e = PyErr_Occurred (); + if (e){ + printf("exception\n"); + return meip; + } + + if (vmcpu.vm_exception_flags) + return meip; + + } + +} + + +PyObject* vm_exec_blocs(PyObject* self, PyObject* args) +{ + PyObject* my_eip; + my_eip = _vm_exec_blocs(self, args); + return my_eip; +} + + + +PyObject* vm_exec_bloc(PyObject* self, PyObject* args) +{ + PyObject* b; + PyObject* module; + PyObject* func; + PyObject* meip; + unsigned int tmp; + + PyObject* my_eip; + PyObject* known_blocs; + PyObject* e; + + if (!PyArg_ParseTuple(args, "OO", &my_eip, &known_blocs)) + return NULL; + + + if (PyInt_Check(my_eip)){ + tmp = (unsigned int)PyInt_AsLong(my_eip); + } + else if (PyLong_Check(my_eip)){ + tmp = (unsigned int)PyInt_AsUnsignedLongLongMask(my_eip); + } + else{ + RAISE(PyExc_TypeError,"arg1 must be int"); + } + + + + //printf("eip val: %x\n", tmp); + meip = PyInt_FromLong((long)tmp); + //printf("x %p\n", meip); + b = PyDict_GetItem(known_blocs, my_eip); + if (b == NULL) + return meip; + + module = PyObject_GetAttrString(b, "module_c"); + if (module == NULL) + return meip; + //Py_DECREF(b); + + func = PyObject_GetAttrString(module, "func"); + if (func == NULL) + return meip; + + Py_DECREF(module); + + + if (!PyCallable_Check (func)) { + printf("function not callable\n"); + exit(0); + } + Py_DECREF(meip); + meip = PyObject_CallObject (func, NULL); + + Py_DECREF(func); + e = PyErr_Occurred (); + if (e){ + printf("exception\n"); + return meip; + } + + return meip; + +} + +/* +PyObject* vm_exec_bloc(PyObject* my_eip, PyObject* known_blocs) +{ + my_eip = _vm_exec_bloc(my_eip, known_blocs); + return my_eip; +} +*/ + + +static PyObject *CodenatError; + + +static PyMethodDef CodenatMethods[] = { + {"vm_init_regs", vm_init_regs, METH_VARARGS, + "init regs vm."}, + {"vm_push_uint32_t", vm_push_uint32_t, METH_VARARGS, + "push on vm stack"}, + {"dump_gpregs_py", dump_gpregs_py, METH_VARARGS, + "x"}, + + + {"vm_push_uint32_t", vm_push_uint32_t, METH_VARARGS, + "x"}, + {"vm_pop_uint32_t",vm_pop_uint32_t, METH_VARARGS, + "X"}, + {"vm_get_gpreg", vm_get_gpreg, METH_VARARGS, + "X"}, + {"vm_set_gpreg",vm_set_gpreg, METH_VARARGS, + "X"}, + {"vm_init_regs",vm_init_regs, METH_VARARGS, + "X"}, + {"dump_gpregs_py", dump_gpregs_py, METH_VARARGS, + "X"}, + + {"init_memory_page_pool_py", init_memory_page_pool_py, METH_VARARGS, + "X"}, + {"init_code_bloc_pool_py",init_code_bloc_pool_py, METH_VARARGS, + "X"}, + {"vm_set_mem_access", vm_set_mem_access, METH_VARARGS, + "X"}, + {"vm_set_mem", vm_set_mem, METH_VARARGS, + "X"}, + {"vm_add_code_bloc",vm_add_code_bloc, METH_VARARGS, + "X"}, + {"vm_exec_bloc",vm_exec_bloc, METH_VARARGS, + "X"}, + {"vm_exec_blocs",vm_exec_blocs, METH_VARARGS, + "X"}, + {"vm_get_str", vm_get_str, METH_VARARGS, + "X"}, + {"vm_add_memory_page",vm_add_memory_page, METH_VARARGS, + "X"}, + {"vm_reset_exception", vm_reset_exception, METH_VARARGS, + "X"}, + {"dump_memory_page_pool_py", dump_memory_page_pool_py, METH_VARARGS, + "X"}, + {"vm_get_all_memory",vm_get_all_memory, METH_VARARGS, + "X"}, + {"reset_memory_page_pool_py", reset_memory_page_pool_py, METH_VARARGS, + "X"}, + {"reset_code_bloc_pool_py", reset_code_bloc_pool_py, METH_VARARGS, + "X"}, + {"call_pyfunc_from_globals",call_pyfunc_from_globals, METH_VARARGS, + "X"}, + + {"vm_get_exception",vm_get_exception, METH_VARARGS, + "X"}, + {"vm_get_exception",vm_get_exception, METH_VARARGS, + "X"}, + {"vm_get_last_write_ad", vm_get_last_write_ad, METH_VARARGS, + "X"}, + {"vm_get_last_write_size",vm_get_last_write_size, METH_VARARGS, + "X"}, + {"vm_get_memory_page_max_address",vm_get_memory_page_max_address, METH_VARARGS, + "X"}, + + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + + +PyMODINIT_FUNC +initlibcodenat_interface(void) +{ + PyObject *m; + + m = Py_InitModule("libcodenat_interface", CodenatMethods); + if (m == NULL) + return; + + CodenatError = PyErr_NewException("codenat.error", NULL, NULL); + Py_INCREF(CodenatError); + PyModule_AddObject(m, "error", CodenatError); +} + diff --git a/miasm/tools/emul_lib/libcodenat_tcc.c b/miasm/tools/emul_lib/libcodenat_tcc.c new file mode 100644 index 00000000..c9766388 --- /dev/null +++ b/miasm/tools/emul_lib/libcodenat_tcc.c @@ -0,0 +1,139 @@ +/* +** Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License along +** with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <Python.h> + +#include <libtcc.h> + + + +/* tcc global state */ +TCCState *tcc_state = NULL; + + +char *emul_lib_dir = NULL; +char *emul_lib_path = NULL; +char *emul_libpython_dir = NULL; + +PyObject* tcc_set_emul_lib_path(PyObject* self, PyObject* args) +{ + char* libdir; + char* libpath; + char* libpython_dir; + if (!PyArg_ParseTuple(args, "sss", &libdir, &libpath, &libpython_dir)) + return NULL; + + emul_lib_dir = (char*)malloc(strlen(libdir)+1); + emul_lib_path = (char*)malloc(strlen(libpath)+1); + emul_libpython_dir = (char*)malloc(strlen(libpython_dir)+1); + strcpy(emul_lib_dir, libdir); + strcpy(emul_lib_path, libpath); + strcpy(emul_libpython_dir, libpython_dir); + return Py_None; +} + +void tcc_init_state(void) +{ + + tcc_state = tcc_new(); + if (!tcc_state) { + fprintf(stderr, "Impossible de creer un contexte TCC\n"); + exit(1); + } + tcc_set_output_type(tcc_state, TCC_OUTPUT_MEMORY); + + tcc_add_include_path(tcc_state, "/usr/include/python2.6"); + tcc_add_include_path(tcc_state, emul_lib_dir); + tcc_add_library_path(tcc_state, emul_lib_dir); + tcc_add_library_path(tcc_state, emul_libpython_dir); + tcc_add_file(tcc_state, emul_lib_path); +} + + + + +PyObject* tcc_exec_bloc(PyObject* self, PyObject* args) +{ + int (*func)(void); + + unsigned long ret; + if (!PyArg_ParseTuple(args, "i", &func)) + return NULL; + ret = func(); + return PyInt_FromLong((long)ret); +} + +PyObject* tcc_compil(PyObject* self, PyObject* args) +{ + char* func_name; + char* func_code; + int (*entry)(void); + void *mem; + int size; + + if (!PyArg_ParseTuple(args, "ss", &func_name, &func_code)) + return NULL; + + tcc_init_state(); + if (tcc_compile_string(tcc_state, func_code) != 0) { + printf("Erreur de compilation !\n"); + exit(0); + } + + size = tcc_relocate(tcc_state, NULL); + if (size == -1) + exit(0); + + mem = malloc(size); + tcc_relocate(tcc_state, mem); + + entry = tcc_get_symbol(tcc_state, func_name); + + tcc_delete(tcc_state); + + return PyInt_FromLong((long)entry); + +} + + +static PyObject *TccError; + + +static PyMethodDef TccMethods[] = { + {"tcc_set_emul_lib_path", tcc_set_emul_lib_path, METH_VARARGS, + "init tcc path"}, + {"tcc_exec_bloc", tcc_exec_bloc, METH_VARARGS, + "tcc exec bloc"}, + {"tcc_compil", tcc_compil, METH_VARARGS, + "tcc compil"}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +PyMODINIT_FUNC +initlibcodenat_tcc(void) +{ + PyObject *m; + + m = Py_InitModule("libcodenat_tcc", TccMethods); + if (m == NULL) + return; + + TccError = PyErr_NewException("tcc.error", NULL, NULL); + Py_INCREF(TccError); + PyModule_AddObject(m, "error", TccError); +} + diff --git a/miasm/tools/emul_lib/main.c b/miasm/tools/emul_lib/main.c new file mode 100644 index 00000000..e088191d --- /dev/null +++ b/miasm/tools/emul_lib/main.c @@ -0,0 +1,43 @@ +/* +** Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License along +** with this program; if not, write to the Free Software Foundation, Inc., +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <Python.h> +#include "queue.h" +#include "libcodenat.h" +int main() +{ + memory_page* mp; + struct memory_page_node * mpn; + + init_memory_page_pool(); + dump_memory_page_pool(); + + + mp = create_memory_page(0x1000, 0x10); + mpn = create_memory_page_node(mp); + add_memory_page(mpn); + + dump_memory_page_pool(); + + + mp = create_memory_page(0x2000, 0x10); + mpn = create_memory_page_node(mp); + add_memory_page(mpn); + dump_memory_page_pool(); + + return 0; +} diff --git a/miasm/tools/emul_lib/queue.h b/miasm/tools/emul_lib/queue.h new file mode 100644 index 00000000..0caf72fb --- /dev/null +++ b/miasm/tools/emul_lib/queue.h @@ -0,0 +1,553 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD$ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +//#include <sys/cdefs.h> + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ +#define QUEUE_MACRO_DEBUG 0 +#if QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char * lastfile; + int lastline; + char * prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT((elm)->field.tqe_next); \ + TRASHIT((elm)->field.tqe_prev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) + +static __inline void +insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void +remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !(__GNUC__ || __INTEL_COMPILER) */ + +void insque(void *a, void *b); +void remque(void *a); + +#endif /* __GNUC__ || __INTEL_COMPILER */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/miasm/tools/func_analyser.py b/miasm/tools/func_analyser.py new file mode 100755 index 00000000..aa34964b --- /dev/null +++ b/miasm/tools/func_analyser.py @@ -0,0 +1,485 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from x86_escape import opcode_factory, bin_stream, instr_dis +from asmbloc import * +from parse_asm import * +import shlex +from ia32_sem import * +from copy import copy +import pefile +import pprint + + +class imp_func: + def __init__(self, address, name, name_dll, unstack=None): + self.address = address + self.name = name + self.dllname = name_dll + self.unstack = unstack + def __str__(self): + return hex(self.address)+' '+str(self.name)+' '+str(self.dllname)+' '+str(self.unstack) + +x86mnemo = opcode_factory() + +fname = "calc.exe" +f = open(fname, 'rb') +pe = pefile.PE(fname) + +pool_import_func = {} +print "read import" +if hasattr(pe, "DIRECTORY_ENTRY_IMPORT"): + for entry in pe.DIRECTORY_ENTRY_IMPORT: + #print entry.dll + for imp in entry.imports: + #print '\t', hex(imp.address), imp.name + pool_import_func[imp.address] = imp_func(imp.address, imp.name, entry.dll) + +dll_pe_cache = {} +dll_rep = "dlls/" +def init_dll_cache(dllname): + global dll_pe_cache + print "read %s"%dllname + pe = pefile.PE(dll_rep+dllname) + dll_pe_cache[dllname] = pe + print 'read ok' + + +def read_dll_export(dll_name, func_name): + global dll_pe_cache + fname = dll_name.lower() + print "read export", fname + + if not fname in dll_pe_cache: + print 'not loaded dll' + init_dll_cache(fname) + + pe = dll_pe_cache[fname] + """ + pe = pefile.PE(fname) + """ + f_tmp = open(dll_rep+fname, 'rb') + + if not hasattr(pe, "DIRECTORY_ENTRY_EXPORT"): + return None + + dict_export = dict([(exp.name, exp) for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols]) + if not func_name in dict_export: + return None + + offset = pe.get_offset_from_rva(dict_export[func_name].address) + print "offset", hex(offset) + in_str_tmp = bin_stream(f_tmp, offset) + symbol_pool_tmp = asm_symbol_pool() + all_bloc_tmp = dis_bloc_all(x86mnemo, in_str_tmp, in_str_tmp.offset, [], symbol_pool_tmp, follow_call = False) + ret = quick_ret_analyse(offset, all_bloc_tmp) + + return ret + + + +print "disasm bin follow " +#0x366 +#0x2F0 +#0x3B0 + +#open file +start_dis = 0x9F09#0xB50 +in_str = bin_stream(f, start_dis) + +#disasm binary +job_done = [] +symbol_pool = asm_symbol_pool() +all_bloc = dis_bloc_all(x86mnemo, in_str, in_str.offset, job_done, symbol_pool, follow_call = False) +print "symbols:" +print symbol_pool + +g = bloc2graph(all_bloc) +open("graph.txt" , "w").write(g) + +jcc = ['jz', 'je', 'jnz', 'jp', 'jnp', 'jg', 'jge', 'ja', 'jae', 'jb', 'jbe', 'jl', 'jle', 'js', 'jns', 'loop'] + +eax_i = ExprId('eax_i') +ebx_i = ExprId('ebx_i') +ecx_i = ExprId('ecx_i') +edx_i = ExprId('edx_i') +esi_i = ExprId('esi_i') +edi_i = ExprId('edi_i') +esp_i = ExprId('esp_i') +ebp_i = ExprId('ebp_i') + +MEM_GLOB = ExprId('MEM_GLOB') + +def dump_pool(p): + print '/-------------\\' + for x in p: + print x, p[x] + print '\\_____________/' + + +def hook_mem_read(evaluator, src): + evaluator.log.warn('mem read %s'%str(src)) + src_address = evaluator.eval_expr(src.arg, {}) + src_address = evaluator.simp_full_exp(src_address) + src_address = evaluator.simp_expr_arith_final(src_address) + + print 'test read',src_address, evaluator.simp_expr_arith_final(src_address) + dump_pool(evaluator.pool[MEM_GLOB]) + + + if not str(src_address) in evaluator.pool[MEM_GLOB]: + evaluator.log.warning('unkown read address:%s'%src_address) + return ExprMem(src_address, size = src.size) + return evaluator.pool[MEM_GLOB][str(src_address)] + + +def hook_mem_write(evaluator, dst, src, pool_out): + evaluator.log.warn("mem write: %s %s"%(str(dst), str(src))) + + dst_address = evaluator.eval_expr(dst.arg, {}) + dst_address = evaluator.simp_full_exp(dst_address) + dst_address = evaluator.simp_expr_arith_final(dst_address) + print 'test write',dst_address, evaluator.simp_expr_arith_final(dst_address) + + evaluator.pool[MEM_GLOB][str(dst_address)] = src + dump_pool(evaluator.pool[MEM_GLOB]) + + + + +#set unkown stack for all blocks +for b in all_bloc: + b.eval_start,b.eval_stop = None, None + for l in b.lines: + l.arg_lookup = None + l.stack_h_after = None + + + +#first bloc start at 0 +#esp_init_arg= 0x1000 +evaluator = eval_int({esp:esp_i, ebp:ebp_i, eax:eax_i, ebx:ebx_i, ecx:ecx_i, edx:edx_i, esi:esi_i, edi:edi_i, + cs:9, + zf : 0, + nf : 0, + pf : 0, + of : 0, + cf : 0, + tf : 0, + i_f: 0, + df : 0, + af : 0, + iopl: 3, + nt : 0, + rf : 0, + vm : 0, + ac : 0, + vif: 0, + vip: 0, + i_d: 0, + MEM_GLOB:{}, + }, + hook_mem_read, + hook_mem_write + ) +args_func = [] +#for i in xrange(3, 0, -1): + #args_func.append(ExprId('arg_%d'%i)) + + #evaluator.eval_instr(push(args_func[-1])) +evaluator.eval_instr(push('ret_addr')) +esp_init= evaluator.pool[esp] + +all_bloc[0].eval_start = evaluator + +def quick_ret_analyse(offset, all_bloc_arg): + #first, try to find ret and look for unstack arg. + for b in all_bloc_arg: + l = b.lines[-1] + if l.m.name == 'ret': + args = [dict_to_Expr(x, l.m.modifs) for x in l.arg] + if len(args) == 0: + return 0 + else: + #exprint + return args[0].arg + #no ret found means special func + #try evaluation to ret and look at esp decal + #hack stack decal + return None + +def is_func_wrapper(ad, pool_import_func = {}): + x86mnemo = opcode_factory() + in_str_tmp = bin_stream(f, ad.offset) + instr = x86mnemo.dis(in_str_tmp) + print 'i'*80 + print instr + if instr.m.name in ['jmp'] and is_address(instr.arg[0]): + return True + + return False + +#is simply import call? +def is_import_call(offset, eval_arg, symbol_pool, pool_import_func = {}): + evaluator_tmp = eval_int(dict([(x,copy(eval_arg.pool[x])) for x in eval_arg.pool]), hook_mem_read, hook_mem_write) + in_str_tmp = bin_stream(f, offset) + + #eval only jmp/call until eip load + ad_done = {} + while True: + if offset in ad_done: + return False, None + ad_done[offset] = True + l = x86mnemo.dis(in_str_tmp) + if not l.m.name in ['call', 'jmp']: + return False, None + + args = [dict_to_Expr(x, l.m.modifs) for x in l.arg] + if l.m.name in ['call']: + if is_imm(l.arg[0]): + e = mnemo_func[l.m.name](ExprInt(in_str_tmp.offset), ExprOp('+', in_str.offset, args[0]) ) + else: + e = mnemo_func[l.m.name](ExprInt(in_str_tmp.offset), args[0]) + else: + e = mnemo_func[l.m.name](*args) + + evaluator_tmp.eval_instr(e) + if eip in evaluator_tmp.pool: + n_eip = evaluator_tmp.pool[eip] + if type(n_eip) in [int, long]: + offset = n_eip + continue + if not isinstance(n_eip, ExprMem): + return False, None + ad = evaluator_tmp.eval_expr(n_eip.arg, {}) + + if not type(ad) in [int, long]: + return False, None + if not ad in pool_import_func: + return False, None + + unstack = None + print "import func spotted:", str(pool_import_func[ad]) + #if pool_import_func[ad].name in known_func: + + print pool_import_func[ad].name + dll_name = pool_import_func[ad].dllname + func_name = pool_import_func[ad].name + unstack = read_dll_export(dll_name, func_name) + print "result:",unstack + #unstack = known_func[pool_import_func[ad].name].unstack + + return True, unstack + iiiopop + #offset = in_str_tmp.offset + + + +def stack_h(b, symbol_pool, pool_import_func = {}): + evaluator_tmp = eval_int(dict([(x,copy(b.eval_start.pool[x])) for x in b.eval_start.pool]), hook_mem_read, hook_mem_write) + #if b.lines[0].offset == 0x9FCE: + # fds + for m in b.lines: + #m.stack_h = evaluator_tmp.pool[esp] + m.stack_h = evaluator.simp_expr_arith_final(evaluator_tmp.pool[esp]) + print hex(m.offset), m.stack_h, str(m) + + + if m.m.name in ['call']: + + """ + #hack call next code + if m.offset+m.l == s.offset: + evaluator_tmp.pool[esp]-=4 + return evaluator_tmp + """ + ret, unstack = is_import_call(m.offset, evaluator_tmp, symbol_pool, pool_import_func) + if unstack!=None: + evaluator_tmp.pool[esp]=evaluator_tmp.eval_expr(ExprOp('+', evaluator_tmp.pool[esp], unstack), {}) + return evaluator_tmp + if ret: + return None + + if not has_symb(m.arg[0]): + return None + dst = m.arg[0][x86_afs.symb].keys() + if len(dst)!=1: + return None + s = symbol_pool.getby_name(dst[0]) + if not s: + return None + + + if is_func_wrapper(s): + return evaluator_tmp + + + in_str_tmp = bin_stream(f, s.offset) + + job_done_tmp = [] + symbol_pool_tmp = asm_symbol_pool() + all_bloc_tmp = dis_bloc_all(x86mnemo, in_str_tmp, in_str_tmp.offset, job_done_tmp, symbol_pool_tmp, follow_call = False) + ret = quick_ret_analyse(s.offset, all_bloc_tmp) + #decal not found + if ret == None: + return ret + #decal is expr + if isinstance(ret, Expr): + #print ret + e = evaluator_tmp.eval_expr(ret, {}) + if type(e) in [int, long]: + print "eval esp oki!", e + ret = e + else: + return None + + #decal found int + if type(ret) in [int, long]: + evaluator_tmp.pool[esp]=evaluator_tmp.eval_expr(ExprOp('+', evaluator_tmp.pool[esp], ret), {}) + return evaluator_tmp + + + if m.m.name in jcc: + continue + + args = [dict_to_Expr(x, m.m.modifs) for x in m.arg] + + e = mnemo_func[m.m.name](*args) + + print "exprs:" + for x in e: + print x + evaluator_tmp.eval_instr(e) + if eip in evaluator_tmp.pool: + print evaluator_tmp.pool[eip] + ret = evaluator_tmp.eval_expr(eip, {}) + if ret == 'ret_addr': + m.stack_h_after = evaluator.simp_expr_arith_final(evaluator_tmp.pool[esp]) + + + return evaluator_tmp + + +def get_expr_diff(evaluator, a, b): + if evaluator == None: + return None + a_e = evaluator.simp_expr_arith_final(evaluator.eval_expr(a, {esp_i:0})) + b_e = evaluator.simp_expr_arith_final(evaluator.eval_expr(b, {esp_i:0})) + if not type(a_e) in [int, long] or not type(b_e) in [int, long]: + return None + return b_e-a_e + + + + + +def resolve_func(all_bloc_arg, symbol_pool, pool_import_func): + all_bloc_dict = dict([(b.label,b) for b in all_bloc_arg]) + while True: + fini = True + for b in all_bloc_arg: + force_stack_h = False + #if one son is known, inform his brothers + if b.eval_stop == None: + for next in b.bto: + if next.label in all_bloc_dict and all_bloc_dict[next.label].eval_start!=None: + b.eval_stop = all_bloc_dict[next.label].eval_start + force_stack_h = True + + for x in b.bto: + if x.label in all_bloc_dict and all_bloc_dict[x.label].eval_start==None: + all_bloc_dict[x.label].eval_start = all_bloc_dict[next.label].eval_start + fini = False + + if b.eval_start == None and b.eval_stop != None: + #try to find stack decal and inform start + print "tttt", hex(b.lines[0].offset) + + b.eval_start = b.eval_stop + tmp = stack_h(b, symbol_pool, pool_import_func) + print '_____',tmp + + decal = get_expr_diff(tmp, tmp.eval_expr(esp, {}),b.eval_stop.eval_expr(esp, {})) + + if decal == None: + b.eval_start = None + fdsfsd + for l in b.lines: + l.stack_h = None + continue + tmp.pool[esp] = ExprOp('+', b.eval_stop.pool[esp] ,decal) + b.eval_start = tmp + print 'decal found ', b.label, decal + fini = False + + if b.eval_start == None: + continue + + if b.eval_stop != None and not force_stack_h: + continue + + + print '*****eval:', b.label, b.eval_start.eval_expr(esp, {}) + b.eval_stop = stack_h(b, symbol_pool, pool_import_func) + if b.eval_stop == None: + continue + print 'propag:', b.label, b.eval_stop.eval_expr(esp, {}) + for next in b.bto: + if next.label in all_bloc_dict: + print next + all_bloc_dict[next.label].eval_start = b.eval_stop + fini = False + + if fini: + break + + lines = reduce(lambda x,y:x+y.lines, all_bloc_arg, []) + return None + + + +print '_'*10 +print resolve_func(all_bloc, symbol_pool, pool_import_func) +print 'result:' +for b in all_bloc: + #print b + if not b.eval_stop or not b.eval_start: + print b.label, 'unresolved bloc' + continue + + #print b.label, esp_init-b.eval_start.pool[esp] + #if eip in b.eval_stop.pool: + # print 'end at:', b.eval_stop.pool[eip], esp_init-b.eval_stop.pool[esp] + +lines = reduce(lambda x,y:x+y.lines, all_bloc, []) +lines = [(l.offset, l) for l in lines] +lines.sort() +for o, l in lines: + if not 'stack_h' in l.__dict__: + l.stack_h = None + print "%-20s"%str(l.stack_h), "%-20s"%str(l.stack_h_after), l + #print "%-5s"%str(l.stack_h) + #print l.arg + +""" +for b in all_bloc: + for l in b.lines: + if not 'stack_h' in l.__dict__: + l.stack_h = None + print l.stack_h, l +""" diff --git a/miasm/tools/hook_helper.py b/miasm/tools/hook_helper.py new file mode 100755 index 00000000..063d5444 --- /dev/null +++ b/miasm/tools/hook_helper.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from miasm.tools.pe_helper import * +from elfesteem import * +from miasm.core import bin_stream +from miasm.arch.ia32_sem import * +from miasm.core import asmbloc +from miasm.core import parse_asm +import re +import sys +from Crypto.Hash import MD5 + + +class hooks(): + def name2str(self, n): + return "str_%s"%n + + def __init__(self, in_str, symbol_pool, gen_data_log_code = True): + self.in_str = in_str + self.all_bloc = [[]] + self.symbol_pool = symbol_pool + if gen_data_log_code: + self.all_bloc, self.symbol_pool = parse_asm.parse_txt(x86mnemo,''' + + f_name: + .string "out.txt" + f_handle: + .long 0x0 + my_critic_sec: + .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + write_ret: + .long 0xDEADBEEF + mtick: + .long 0xdeadbeef + + + log_name_data_len: + push ebp + mov ebp, esp + pushad + + + + mov eax, [f_handle] + test eax, eax + jnz write_file_2 + ;; create log file + push 0 + push 0x80 + push 4 + push 0 + push 1 + push 4 + lea ebx, [f_name] + push ebx + call [CreateFileA] + mov [f_handle], eax + + ;; create lock + push my_critic_sec + call [initializecriticalsection] + + write_file_2: + ;; lock + push my_critic_sec + call [entercriticalsection] + + + ;; write log name + push [ebp+8] + call [lstrlenA] + inc eax + + push 0 + lea ebx, [write_ret] + push ebx + push eax + push [ebp+8] + push [f_handle] + call [WriteFile] + + + ;; write tickcount + call [GetTickCount] + mov [mtick], eax + push 0 + lea ebx, [write_ret] + push ebx + push 4 + lea ebx, [mtick] + push ebx + push [f_handle] + call [WriteFile] + + + ;; write data size + push 0 + lea ebx, [write_ret] + push ebx + push 4 + lea ebx, [ebp+0x10] + push ebx + push [f_handle] + call [WriteFile] + + + ;;write data + push 0 + lea ebx, [write_ret] + push ebx + push [ebp+0x10] + push [ebp+0xc] + push [f_handle] + call [WriteFile] + + ;; unlock + push my_critic_sec + call [leavecriticalsection] + + + popad + mov esp, ebp + pop ebp + ret 0xc + + ''', symbol_pool = symbol_pool) + + + def add_hook(self, hook_ad, args_to_hook = {}, vars_decl = [], func_code = "", post_hook = ""): + wrapper_name = "wrapper_%.8X"%hook_ad + wrapper_log_name = "wrapper_log_%.8X"%hook_ad + patch_name = "patch_%.8X"%hook_ad + patch_end_name = "patch_end_%.8X"%hook_ad + + log_name = "log_%.8X"%hook_ad + + string_decl = [] + to_hook = args_to_hook.keys() + to_hook.sort() + + for s in to_hook: + if s.endswith('DONT_LOG'): + continue + string_decl.append('%s:\n.string "%s"'%(self.name2str(s), s)) + string_decl = "\n".join(string_decl) + + + lines, total_bytes = asmbloc.steal_bytes(self.in_str, x86_mn, hook_ad, 5) + erased_asm = "\n".join([str(l) for l in lines]) + print 'stolen lines' + print erased_asm + + self.symbol_pool.getby_name_create(patch_name).offset = hook_ad + self.symbol_pool.getby_name_create(patch_end_name).offset = hook_ad+total_bytes + + + asm_s = ''' +%s: + call %s +'''%(wrapper_name, wrapper_log_name)+erased_asm+"\n"+post_hook+"\n"+''' + jmp %s'''%(patch_end_name)+''' +%s: + ;;int 3 + pushad + pushfd + '''%wrapper_log_name + + for s in to_hook[::-1]: + asm_s += args_to_hook[s][1] + asm_s +=''' + call %s + popfd + popad + ret +'''%(log_name)+string_decl+'\n'+'\n'.join(vars_decl)+''' +%s: + push ebp + mov ebp, esp + +'''%(log_name) + asm_s += func_code +'\n' + + for i, c in enumerate(to_hook): + len_howto, arg_asm = args_to_hook[c] + if type(len_howto) in [int, long]: + asm_s += ''' + push %d + '''%(len_howto) + elif isinstance(len_howto, str): + asm_s += len_howto + + if not c.endswith('DONT_LOG'): + asm_s += ''' + push [ebp+%d] + push %s + call log_name_data_len + '''%(8+4*i, self.name2str(c)) + + + asm_s +=""" + pop ebp + ret %d + + """%(len(to_hook)*4) + + asm_s +=""" + %s: + jmp %s + %s: + .split + """%(patch_name, wrapper_name, patch_end_name) + + #print asm_s + + all_bloc, self.symbol_pool = parse_asm.parse_txt(x86mnemo,asm_s, symbol_pool = self.symbol_pool) + self.all_bloc[0] += all_bloc[0] + return log_name + + + + diff --git a/miasm/tools/nux_api.py b/miasm/tools/nux_api.py new file mode 100644 index 00000000..98fd2ce0 --- /dev/null +++ b/miasm/tools/nux_api.py @@ -0,0 +1,917 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from to_c_helper import * +import struct +import inspect +import socket +import time +import random +import os +import sys +ctime_str = None +def fd_generator(): + i = 0 + while True: + yield i + i+=1 + +fd_gen = fd_generator() +fd_stdin = fd_gen.next() +fd_stout = fd_gen.next() + + +socket_pool = {} +def get_str_ansi(ad_str, max_l = None): + l = 0 + tmp = ad_str + while vm_get_str(tmp, 1) != "\x00": + tmp +=1 + l+=1 + if max_l and l > max_l: + break + return vm_get_str(ad_str, l) + +def get_dw_stack(offset): + esp = vm_get_gpreg()['esp'] + return updw(vm_get_str(esp+offset, 4)) + + +def whoami(): + return inspect.stack()[1][3] + + + +def xxx_memset(): + ret_ad = vm_pop_uint32_t() + arg_addr = get_dw_stack(0) + arg_c = get_dw_stack(4) + arg_size = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', hex(arg_addr), arg_c, arg_size, ')' + vm_set_mem(arg_addr, chr(arg_c)*arg_size) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = arg_addr + vm_set_gpreg(regs) + +def xxx_printf(): + ret_ad = vm_pop_uint32_t() + fmt_p = get_dw_stack(0) + fmt_s = get_str_ansi(fmt_p) + + print whoami(), hex(ret_ad), '(', repr(fmt_s), ')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def xxx_socket(): + ret_ad = vm_pop_uint32_t() + arg_domain = get_dw_stack(0) + arg_type = get_dw_stack(4) + arg_proto = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', arg_domain, arg_type, arg_proto,')' + fd = fd_gen.next() + regs = vm_get_gpreg() + regs['eip'] = ret_ad + #regs['eax'] = fd + # XXX DANGEROUS + s = socket.socket(arg_domain, arg_type, arg_proto) + socket_pool[s.fileno()] = s + regs['eax'] = s.fileno() + + + vm_set_gpreg(regs) + + +def xxx_htonl(): + ret_ad = vm_pop_uint32_t() + arg_dw = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', arg_dw,')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = socket.htonl(arg_dw) + vm_set_gpreg(regs) + +def xxx_htons(): + ret_ad = vm_pop_uint32_t() + arg_dw = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', arg_dw,')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = socket.htons(arg_dw) + vm_set_gpreg(regs) + +def xxx_bind(): + ret_ad = vm_pop_uint32_t() + arg_sockfd = get_dw_stack(0) + arg_addr = get_dw_stack(4) + arg_addrlen = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', arg_sockfd, hex(arg_addr), arg_addrlen,')' + + addr_s = vm_get_str(arg_addr, arg_addrlen) + print repr(addr_s) + sin_f, sin_port, sin_addr = struct.unpack('>HHL', addr_s[:8]) + print repr(sin_f), repr(sin_port), repr(sin_addr) + # XXX + #sin_port = 2222 + socket_pool[arg_sockfd].bind(('', sin_port)) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def xxx_listen(): + ret_ad = vm_pop_uint32_t() + arg_sockfd = get_dw_stack(0) + arg_backlog = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', arg_sockfd, arg_backlog, ')' + socket_pool[arg_sockfd].listen(arg_backlog) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def xxx_accept(): + ret_ad = vm_pop_uint32_t() + arg_sockfd = get_dw_stack(0) + arg_addr = get_dw_stack(4) + arg_addrlen = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', arg_sockfd, hex(arg_addr), arg_addrlen, ')' + conn, addr = socket_pool[arg_sockfd].accept() + socket_pool[conn.fileno()] = conn + + print 'ACCEPT', conn, addr + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = conn.fileno() + vm_set_gpreg(regs) + + +def xxx_puts(): + ret_ad = vm_pop_uint32_t() + arg_s = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', arg_s, ')' + s = get_str_ansi(arg_s) + print 'PUTS', repr(s) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def xxx_recv(): + ret_ad = vm_pop_uint32_t() + arg_sockfd = get_dw_stack(0) + arg_buf = get_dw_stack(4) + arg_len = get_dw_stack(8) + arg_flags = get_dw_stack(12) + + print whoami(), hex(ret_ad), '(', arg_sockfd, arg_buf, arg_len, arg_sockfd, ')' + buf = socket_pool[arg_sockfd].recv(arg_len) + + print 'RECV', repr(buf) + vm_set_mem(arg_buf, buf) + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + if buf: + regs['eax'] = len(buf) + else: + regs['eax'] = -1 + vm_set_gpreg(regs) + + +def xxx_send(): + ret_ad = vm_pop_uint32_t() + arg_sockfd = get_dw_stack(0) + arg_buf = get_dw_stack(4) + arg_len = get_dw_stack(8) + arg_flags = get_dw_stack(12) + + print whoami(), hex(ret_ad), '(', arg_sockfd, arg_buf, arg_len, arg_sockfd, ')' + buf = vm_get_str(arg_buf, arg_len) + try: + socket_pool[arg_sockfd].send(buf) + except: + print 'send fail' + buf = "" + + print 'SEND', repr(buf) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = len(buf) + vm_set_gpreg(regs) + +def xxx_close(): + ret_ad = vm_pop_uint32_t() + arg_sockfd = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', arg_sockfd, ')' + socket_pool[arg_sockfd].close() + + print 'close', repr(arg_sockfd) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def xxx_signal(): + ret_ad = vm_pop_uint32_t() + arg_signum = get_dw_stack(0) + arg_sigh = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', arg_signum, hex(arg_sigh), ')' + # XXX todo + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def xxx_setsockopt(): + ret_ad = vm_pop_uint32_t() + arg_sockfd = get_dw_stack(0) + arg_level = get_dw_stack(4) + arg_optname = get_dw_stack(8) + arg_optval = get_dw_stack(12) + arg_optlen = get_dw_stack(16) + + print whoami(), hex(ret_ad), '(', arg_sockfd, hex(arg_level), arg_optname, hex(arg_optval), arg_optlen, ')' + opt_val = vm_get_str(arg_optval, arg_optlen) + print repr(opt_val) + + # Translation between C and python values + # #define SOL_SOCKET 0xffff + dct_level = {0xffff:1, 1:1} + dct_argname = {4:2, 2:2} + arg_level = dct_level[arg_level] + arg_optname = dct_argname[arg_optname] + + print repr(arg_level), repr(arg_optname), repr(opt_val) + socket_pool[arg_sockfd].setsockopt(arg_level, arg_optname, opt_val) + # XXX todo + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def xxx_getpwnam(): + ret_ad = vm_pop_uint32_t() + arg_name = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', hex(arg_name), ')' + s = get_str_ansi(arg_name) + print repr(s) + # create fake struct + + name = s + password = "pwd_"+name + rname = name + udir = "/home/"+name + ushell = "shell_"+name + + ad = vm_get_memory_page_max_address() + + vm_add_memory_page(ad, PAGE_READ|PAGE_WRITE, 0x1000*"\x00") + ad = (ad+0xfff) & 0xfffff000 + s = struct.pack('IIIIIII', + ad+0x100, + ad+0x200, + 1337, + 1337, + ad+0x300, + ad+0x400, + ad+0x500) + + s = struct.pack('256s256s256s256s256s256s', s, name, password, rname, udir, ushell) + print repr(s) + vm_set_mem(ad, s) + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = ad + vm_set_gpreg(regs) + +def xxx_getuid(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad), '(', ')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1337 + vm_set_gpreg(regs) + +def xxx_getgid(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad), '(', ')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1337 + vm_set_gpreg(regs) + +def xxx_initgroups(): + ret_ad = vm_pop_uint32_t() + arg_name = get_dw_stack(0) + arg_group = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', hex(arg_name), arg_group, ')' + s = get_str_ansi(arg_name) + print repr(s) + # XXX todo + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def xxx_setresgid(): + ret_ad = vm_pop_uint32_t() + arg_ruid = get_dw_stack(0) + arg_euid = get_dw_stack(4) + arg_suid = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', arg_ruid, arg_euid, arg_suid, ')' + # XXX todo + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def xxx_setresuid(): + ret_ad = vm_pop_uint32_t() + arg_ruid = get_dw_stack(0) + arg_euid = get_dw_stack(4) + arg_suid = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', arg_ruid, arg_euid, arg_suid, ')' + # XXX todo + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def xxx_getegid(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad), '(', ')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1337 + vm_set_gpreg(regs) + +def xxx_geteuid(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad), '(', ')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1337 + vm_set_gpreg(regs) + +def xxx_chdir(): + ret_ad = vm_pop_uint32_t() + arg_path = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', hex(arg_path), ')' + if arg_path: + s = get_str_ansi(arg_path) + else: + s = "default_path" + print repr(s) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def xxx_time(): + ret_ad = vm_pop_uint32_t() + arg_time = get_dw_stack(0) + print whoami(), hex(ret_ad), '(', hex(arg_time), ')' + + t = int(time.time()) + if arg_time: + vm_set_mem(arg_time, pdw(t)) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = t + vm_set_gpreg(regs) + +def xxx_ctime(): + global ctime_str + ret_ad = vm_pop_uint32_t() + arg_time = get_dw_stack(0) + print whoami(), hex(ret_ad), '(', hex(arg_time), ')' + + if not ctime_str: + ad = vm_get_memory_page_max_address() + vm_add_memory_page(ad, PAGE_READ|PAGE_WRITE, 0x1000*"\x00") + ctime_str = ad + + t = vm_get_str(arg_time, 4) + t = updw(t) + print hex(t) + s = time.ctime(t) + vm_set_mem(ctime_str, s) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = ctime_str + vm_set_gpreg(regs) + +def xxx_srand(): + ret_ad = vm_pop_uint32_t() + arg_seed = get_dw_stack(0) + print whoami(), hex(ret_ad), '(', hex(arg_seed), ')' + + random.seed(arg_seed) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def xxx_rand(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad), '(', ')' + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = random.randint(0, 0xffffffff) + vm_set_gpreg(regs) + +def xxx_fork(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad), '(', ')' + + + ret = os.fork() + #ret= 0 + print 'FORK', ret + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = ret + vm_set_gpreg(regs) + + + +def xxx_strncpy(): + ret_ad = vm_pop_uint32_t() + arg_dst = get_dw_stack(0) + arg_src = get_dw_stack(4) + arg_n = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', hex(arg_dst), hex(arg_src), arg_n, ')' + src = get_str_ansi(arg_src, arg_n) + src = (src+'\x00'*arg_n)[:arg_n] + + vm_set_mem(arg_dst, src) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = arg_dst + vm_set_gpreg(regs) + +def xxx_strlen(): + ret_ad = vm_pop_uint32_t() + arg_src = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', hex(arg_src), ')' + src = get_str_ansi(arg_src) + print repr(src) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = len(src) + vm_set_gpreg(regs) + + +def xxx_read(): + ret_ad = vm_pop_uint32_t() + arg_fd = get_dw_stack(0) + arg_buf = get_dw_stack(4) + arg_len = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', arg_fd, arg_buf, arg_len, ')' + buf = os.read(arg_fd, arg_len) + + print 'RECV', repr(buf) + vm_set_mem(arg_buf, buf) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = len(buf) + vm_set_gpreg(regs) + +def xxx_strcmp(): + ret_ad = vm_pop_uint32_t() + arg_s1 = get_dw_stack(0) + arg_s2 = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', hex(arg_s1), hex(arg_s2), ')' + s1 = get_str_ansi(arg_s1) + s2 = get_str_ansi(arg_s2) + print repr(s1), repr(s2) + if s1 == s2: + ret = 0 + elif s1 > s2: + ret = 1 + else: + ret = -1 + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = ret + vm_set_gpreg(regs) + +def xxx_exit(): + ret_ad = vm_pop_uint32_t() + arg_code = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', hex(arg_code), ')' + + sys.exit(arg_code) + +def xxx__exit(): + xxx_exit() + + +def xxx_fdopen(): + ret_ad = vm_pop_uint32_t() + arg_fd = get_dw_stack(0) + arg_mode = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', arg_fd, hex(arg_mode), ')' + m = get_str_ansi(arg_mode) + print repr(m) + + s = os.fdopen(arg_fd, m, 0) + socket_pool[id(s)] = s + + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = id(s) + vm_set_gpreg(regs) + +def xxx_fclose(): + ret_ad = vm_pop_uint32_t() + arg_fd = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', arg_fd, ')' + socket_pool[arg_fd].close() + + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def parse_fmt(s): + fmt = s[:]+"\x00" + out = [] + i = 0 + while i < len(fmt): + c = fmt[i] + if c != "%": + i+=1 + continue + if fmt[i+1] == "%": + i+=2 + continue + j = 0 + i+=1 + while fmt[i+j] in "0123456789$.": + j+=1 + if fmt[i+j] == "h": + x = fmt[i+j:i+j+2] + else: + x = fmt[i+j] + i+=j + out.append(x) + return out + + +def xxx_fprintf(): + ret_ad = vm_pop_uint32_t() + arg_stream = get_dw_stack(0) + arg_fmt = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', arg_stream, hex(arg_fmt), ')' + s = get_str_ansi(arg_fmt) + print repr(s) + fmt_a = parse_fmt(s) + offset = 8 + args = [] + for i, x in enumerate(fmt_a): + a = get_dw_stack(offset+4*i) + if x == "s": + a = get_str_ansi(a) + args.append(a) + print repr(s), repr(args) + + oo = s%(tuple(args)) + print repr(oo) + socket_pool[arg_stream].write(oo) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = len(oo) + vm_set_gpreg(regs) + +def xxx_fgets(): + ret_ad = vm_pop_uint32_t() + arg_buf = get_dw_stack(0) + arg_size = get_dw_stack(4) + arg_stream = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', hex(arg_buf), arg_size, arg_stream, ')' + buf = "" + while len(buf) < arg_size-1: + buf += socket_pool[arg_stream].read(1) + if not buf: + break + if "\n" in buf: + break + if "\x00" in buf: + break + if buf: + buf += "\x00" + print repr(buf) + vm_set_mem(arg_buf, buf) + + if not buf: + arg_buf = 0 + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = arg_buf + vm_set_gpreg(regs) + +def xxx_fwrite(): + ret_ad = vm_pop_uint32_t() + arg_buf = get_dw_stack(0) + arg_size = get_dw_stack(4) + arg_nmemb = get_dw_stack(8) + arg_stream = get_dw_stack(12) + + print whoami(), hex(ret_ad), '(', hex(arg_buf), arg_size, arg_nmemb, arg_stream, ')' + + buf = vm_get_str(arg_buf, arg_size*arg_nmemb) + print repr(buf) + socket_pool[arg_stream].write(buf) + """ + except: + print "err in write" + buf = "" + """ + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = len(buf) + vm_set_gpreg(regs) + +def xxx_fflush(): + ret_ad = vm_pop_uint32_t() + arg_stream = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', arg_stream, ')' + + socket_pool[arg_stream].flush() + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def xxx_malloc(): + ret_ad = vm_pop_uint32_t() + arg_size = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', arg_size, ')' + + + ad = vm_get_memory_page_max_address() + ad = (ad+0xfff) & 0xfffff000 + vm_add_memory_page(ad, PAGE_READ|PAGE_WRITE, arg_size*"\x00") + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = ad + vm_set_gpreg(regs) + +def xxx_bzero(): + ret_ad = vm_pop_uint32_t() + arg_addr = get_dw_stack(0) + arg_size = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', hex(arg_addr), arg_size, ')' + + vm_set_mem(arg_addr, "\x00"*arg_size) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def xxx_fopen(): + ret_ad = vm_pop_uint32_t() + arg_path = get_dw_stack(0) + arg_mode = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', arg_path, hex(arg_mode), ')' + path = get_str_ansi(arg_path) + m = get_str_ansi(arg_mode) + print repr(path), repr(m) + path = "/home/serpilliere/projet/pelogger/user.db" + try: + s = open(path, m, 0) + socket_pool[id(s)] = s + s= id(s) + except: + s = 0 + + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = s + vm_set_gpreg(regs) + +def xxx_fread(): + ret_ad = vm_pop_uint32_t() + arg_buf = get_dw_stack(0) + arg_size = get_dw_stack(4) + arg_nmemb = get_dw_stack(8) + arg_stream = get_dw_stack(12) + + print whoami(), hex(ret_ad), '(', hex(arg_buf), arg_size, arg_nmemb, arg_stream, ')' + + buf = socket_pool[arg_stream].read(arg_size*arg_nmemb) + print repr(buf) + vm_set_mem(arg_buf, buf) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = len(buf) + vm_set_gpreg(regs) + + +def xxx_atoi(): + ret_ad = vm_pop_uint32_t() + arg_nptr = get_dw_stack(0) + + print whoami(), hex(ret_ad), '(', arg_nptr, ')' + buf = get_str_ansi(arg_nptr) + print repr(buf) + i = int(buf) + print i + + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = i + vm_set_gpreg(regs) + + +def xxx_strcpy(): + ret_ad = vm_pop_uint32_t() + arg_dst = get_dw_stack(0) + arg_src = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', hex(arg_dst), hex(arg_src), ')' + src = get_str_ansi(arg_src) + vm_set_mem(arg_dst, src+"\x00") + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = arg_dst + vm_set_gpreg(regs) + + +def xxx_vasprintf(): + ret_ad = vm_pop_uint32_t() + arg_strp = get_dw_stack(0) + arg_fmt = get_dw_stack(4) + arg_ap = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', hex(arg_strp), hex(arg_fmt), hex(arg_ap), ')' + fmt = get_str_ansi(arg_fmt) + print repr(fmt) + + fmt_a = parse_fmt(fmt) + + args = [] + for i, x in enumerate(fmt_a): + a = updw(vm_get_str(arg_ap+4*i, 4)) + if x == "s": + a = get_str_ansi(a) + args.append(a) + + + s = fmt%(tuple(args))+"\x00" + print repr(s) + ad = vm_get_memory_page_max_address() + ad = (ad+0xfff) & 0xfffff000 + vm_add_memory_page(ad, PAGE_READ|PAGE_WRITE, (len(s)+1)*"\x00") + + vm_set_mem(arg_strp, pdw(ad)) + vm_set_mem(ad, s) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = len(fmt) + vm_set_gpreg(regs) + + +def xxx_sprintf(): + ret_ad = vm_pop_uint32_t() + arg_str = get_dw_stack(0) + arg_fmt = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', hex(arg_str), hex(arg_fmt), ')' + s = get_str_ansi(arg_fmt) + print repr(s) + fmt_a = parse_fmt(s) + offset = 8 + args = [] + for i, x in enumerate(fmt_a): + a = get_dw_stack(offset+4*i) + if x == "s": + a = get_str_ansi(a) + args.append(a) + print repr(s), repr(args) + + oo = s%(tuple(args)) + print repr(oo) + vm_set_mem(arg_str, oo+"\x00") + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = len(oo) + vm_set_gpreg(regs) + + +def xxx_strcat(): + ret_ad = vm_pop_uint32_t() + arg_dst = get_dw_stack(0) + arg_src = get_dw_stack(4) + + print whoami(), hex(ret_ad), '(', hex(arg_dst), hex(arg_src), ')' + src = get_str_ansi(arg_src) + dst = get_str_ansi(arg_dst) + print repr(dst), repr(src) + vm_set_mem(arg_dst, dst+src+'\x00') + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = arg_dst + vm_set_gpreg(regs) + +def xxx_strncmp(): + ret_ad = vm_pop_uint32_t() + arg_s1 = get_dw_stack(0) + arg_s2 = get_dw_stack(4) + arg_n = get_dw_stack(8) + + print whoami(), hex(ret_ad), '(', hex(arg_s1), hex(arg_s2), arg_n, ')' + + s1 = get_str_ansi(arg_s1, arg_n) + s2 = get_str_ansi(arg_s2, arg_n) + print repr(s1), repr(s2) + if s1 == s2: + ret = 0 + elif s1 > s2: + ret = 1 + else: + ret = -1 + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = ret + vm_set_gpreg(regs) diff --git a/miasm/tools/pe_helper.py b/miasm/tools/pe_helper.py new file mode 100644 index 00000000..aba8d1b7 --- /dev/null +++ b/miasm/tools/pe_helper.py @@ -0,0 +1,593 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from elfesteem import * + +from miasm.arch.ia32_arch import * +from miasm.tools.emul_helper import * +from miasm.arch.ia32_sem import * +import struct +import miasm.core.asmbloc +import miasm.core.bin_stream +import os +import re +from miasm.tools import to_c_helper +import miasm.core.bin_stream +pe_cache = {} +def pe_from_name(n): + global pe_cache + + my_path = 'win_dll/' + all_pe = os.listdir(my_path) + if not n in all_pe: + print 'cannot find PE', n + return None + + pe_name = my_path+n + if pe_name in pe_cache: + return pe_cache[pe_name] + e = pe_init.PE(open(pe_name, 'rb').read()) + pe_cache[pe_name] = e + return e + + +def func_from_import(pe_name, func): + e = pe_from_name(pe_name) + + if not e or not e.DirExport: + print 'no export dir found' + return None, None + + + found = None + if type(func) is str: + for i, n in enumerate(e.DirExport.f_names): + if n.name.name == func: + found = e.DirExport.f_address[e.DirExport.f_nameordinals[i].ordinal] + break + + elif type(func) in [int, long]: + for i, n in enumerate(e.DirExport.f_names): + if e.DirExport.f_nameordinals[i].ordinal+e.DirExport.expdesc.base == func: + found = e.DirExport.f_address[e.DirExport.f_nameordinals[i].ordinal] + break + else: + raise ValueError('unknown fund type', func) + + #XXX todo: test if redirected export + return e, found + + + +def is_rva_in_code_section(e, rva): + s = e.getsectionbyrva(rva) + return s.flags&0x20!=0 + +def guess_func_destack_dis(e, ad): + job_done = set() + symbol_pool = asmbloc.asm_symbol_pool() + in_str = bin_stream.bin_stream(e.virt) + + all_bloc = asmbloc.dis_bloc_all(x86_mn, in_str, ad, job_done, symbol_pool, follow_call = False, patch_instr_symb = False) + return guess_func_destack(all_bloc) + + +def guess_imports_ret_unstack(e): + unresolved = set() + resolved = {} + redirected = {} + for i,s in enumerate(e.DirImport.impdesc): + l = "%2d %-25s %s"%(i, repr(s.dlldescname) ,repr(s)) + libname = s.dlldescname.name + + + for ii, f in enumerate(s.impbynames): + print '_'*20 + funcname = f.name + + + my_e, ret = func_from_import(libname.lower(), funcname) + if ret: + func_addr = my_e.rva2virt(ret.rva) + print funcname, hex(func_addr) + else: + print 'not found' + continue + + #XXX python int obj len zarb bug + imgb = my_e.NThdr.ImageBase + if imgb>0x80000000: + imgb-=0x40000000 + func_addr-=0x40000000 + my_e.NThdr.ImageBase = imgb + + if not is_rva_in_code_section(my_e, ret.rva): + print "not in code section" + continue + + + ok, r = guess_func_destack_dis(my_e, func_addr) + print funcname, 'ret', r + if ok == True: + resolved[(libname, funcname)] = r + elif ok == None: + unresolved.add((libname, funcname)) + else: + resolved[(libname, funcname)] = r + + + return resolved, unresolved, redirected + + +def get_import_address(e): + import2addr = {} + + for i,s in enumerate(e.DirImport.impdesc): + fthunk = e.rva2virt(s.firstthunk) + l = "%2d %-25s %s"%(i, repr(s.dlldescname) ,repr(s)) + + libname = s.dlldescname.name.lower() + for ii, imp in enumerate(s.impbynames): + if isinstance(imp, pe_init.ImportByName): + funcname = imp.name + else: + funcname = imp + l = " %2d %-16s"%(ii, repr(funcname)) + + + import2addr[(libname, funcname)] = e.rva2virt(s.firstthunk+4*ii) + return import2addr + + +def get_import_address_elf(e): + import2addr = {} + for k, v in e.sh.rel_plt.rel.items(): + import2addr[('xxx', k)] = v.offset + return import2addr + + +def get_symbols_elf(e): + sym2addr = {} + for k, v in e.sh.dynsym.symbols.items(): + sym2addr[k] = v + return sym2addr + +def guess_redirected(e, resolved, unresolved, redirected, import2addr): + + import2addr_inv = [(x[1], x[0]) for x in import2addr.items()] + + + to_del = [] + for imp in redirected: + ad = redirected[imp] + if ad in import2addr_inv: + my_imp = import2addr[ad] + if not my_imp in resolved: + continue + else: + resolved[my_imp] = resolved[imp] + to_del.append(my_imp) + + + redirected = [x for x in redirected if not x in to_del] + + return resolved, unresolved, redirected + + +if __name__ == '__main__': + e, ret = func_from_import('hal.dll', 'KfAcquireSpinLock') + if ret: + print dir(ret) + print hex(e.rva2virt(ret.rva)) + +def get_imp_to_dict(e): + imp2ad = get_import_address(e) + imp_d = {} + + for libf, ad in imp2ad.items(): + libname, f = libf + imp_d[ad] = libf + return imp_d + + + + +def get_imp_bloc(all_bloc, new_lib, imp_d, symbol_pool): + f_imps = [] + symb_equiv = {} + for b in all_bloc: + for l in b.lines: + for a in l.arg: + if not x86_afs.ad in a or not a[x86_afs.ad]: + continue + print a + if not x86_afs.imm in a: + continue + ad = a[x86_afs.imm] + if not ad in imp_d: + continue + print 'spot', ad, l + lab = symbol_pool.getby_offset_create(ad) + print lab + + + l = symbol_pool.getby_offset(ad) + print "ioioio", l + l.offset = None + + a[x86_afs.symb] = {lab.name:1} + print a + del a[x86_afs.imm] + + libname, func = imp_d[ad] + print func + new_lib.append( + ({"name":libname, + "firstthunk":None}, + [func]), + ) + f_imps.append(func) + symb_equiv[func] = l + return f_imps, symb_equiv + + +def code_is_line(e, ad): + job_done = set() + in_str = bin_stream.bin_stream(e.virt) + symbol_pool = asmbloc.asm_symbol_pool() + all_bloc = asmbloc.dis_bloc_all(x86_mn, in_str, ad, job_done, symbol_pool, bloc_wd = 2) + if len(all_bloc) !=1: + return None + if len(all_bloc[0].lines)!=1: + return None + return all_bloc + +def is_jmp_imp(l, imp_d): + if not l.m.name == 'jmp': + return False + if not is_address(l.arg[0]): + return False + ad = dict(l.arg[0]) + del ad[x86_afs.ad] + if not is_imm(ad): + return False + print ad + i = ad[x86_afs.imm] + if not i in imp_d: + return False + print imp_d[i] + return imp_d[i] + + +def code_is_jmp_imp(e, ad, imp_d): + all_bloc = code_is_line(e, ad) + if not all_bloc: + return None + l = all_bloc[0].lines[0] + return is_jmp_imp(l, imp_d) + + +#giving e and address in function guess function start +def guess_func_start(e, middle_ad, max_offset = 0x200): + ad = middle_ad+1 + ad_found = None + while ad > middle_ad - max_offset: + ad-=1 + + ####### heuristic CC pad ####### + if e.virt[ad] == "\xCC": + if e.virt[((ad+3)&~3)-1] == "\xCC": + ad_found = ((ad+3)&~3) + break + else: + continue + + + l = x86_mn.dis(e.virt[ad:ad+15]) + if not l: + continue + if l.m.name in ["ret"]: + ad_found = ad+l.l + break + + if not ad_found: + print 'cannot find func start' + return None + + while e.virt[ad_found] == "\xCC": + ad_found+=1 + + if e.virt[ad_found:ad_found+3] == "\x8D\x40\x00": + ad_found += 3 + + + return ad_found + +def get_nul_term(e, ad): + out = "" + while True: + c = e.virt[ad] + if c == None: + return None + if c == "\x00": + break + out+=c + ad+=1 + return out + +#return None if is not str +def guess_is_string(out): + if out == None or len(out) == 0: + return None + cpt = 0 + for c in out: + if c.isalnum(): + cpt+=1 + if cpt * 100 / len(out) > 40: + return out + + return None + + +def get_guess_string(e, ad): + s = get_nul_term(e, ad) + return guess_is_string(s) + + + + + + +def canon_libname_libfunc(libname, libfunc): + dn = libname.split('.')[0] + fn = "%s"%libfunc + return "%s_%s"%(dn, fn) + + +class libimp: + def __init__(self, lib_base_ad = 0x77700000): + self.name2off = {} + self.libbase2lastad = {} + self.libbase_ad = lib_base_ad + self.lib_imp2ad = {} + self.lib_imp2dstad = {} + self.fad2cname = {} + + def lib_get_add_base(self, name): + name = name.lower() + if name in self.name2off: + ad = self.name2off[name] + else: + print 'new lib', name + ad = self.libbase_ad + self.name2off[name] = ad + self.libbase2lastad[ad] = ad+0x1 + self.lib_imp2ad[ad] = {} + self.lib_imp2dstad[ad] = {} + self.libbase_ad += 0x1000 + return ad + + def lib_get_add_func(self, libad, imp_ord_or_name, dst_ad = None): + if not libad in self.name2off.values(): + raise ValueError('unknown lib base!', hex(libad)) + + #test if not ordinatl + #if imp_ord_or_name >0x10000: + # imp_ord_or_name = vm_get_str(imp_ord_or_name, 0x100) + # imp_ord_or_name = imp_ord_or_name[:imp_ord_or_name.find('\x00')] + + + #/!\ can have multiple dst ad + if not imp_ord_or_name in self.lib_imp2dstad[libad]: + self.lib_imp2dstad[libad][imp_ord_or_name] = set() + self.lib_imp2dstad[libad][imp_ord_or_name].add(dst_ad) + + + if imp_ord_or_name in self.lib_imp2ad[libad]: + return self.lib_imp2ad[libad][imp_ord_or_name] + print 'new imp', imp_ord_or_name, dst_ad + ad = self.libbase2lastad[libad] + self.libbase2lastad[libad] += 0x1 + self.lib_imp2ad[libad][imp_ord_or_name] = ad + + name_inv = dict([(x[1], x[0]) for x in self.name2off.items()]) + c_name = canon_libname_libfunc(name_inv[libad], imp_ord_or_name) + self.fad2cname[ad] = c_name + return ad + + def check_dst_ad(self): + for ad in self.lib_imp2dstad: + all_ads = self.lib_imp2dstad[ad].values() + all_ads.sort() + for i, x in enumerate(all_ads[:-1]): + if x == None or all_ads[i+1] == None: + return False + if x+4 != all_ads[i+1]: + return False + return True + + def gen_new_lib(self, e): + new_lib = [] + for n, ad in self.name2off.items(): + all_ads = self.lib_imp2dstad[ad].values() + all_ads = reduce(lambda x,y:x+list(y), all_ads, []) + all_ads.sort() + #first, drop None + for i,x in enumerate(all_ads): + if not x in [0, None]: + break + all_ads = all_ads[i:] + while all_ads: + othunk = all_ads[0] + i = 0 + while i+1 < len(all_ads) and all_ads[i]+4 == all_ads[i+1]: + i+=1 + out_ads = dict() + for k, vs in self.lib_imp2dstad[ad].items(): + for v in vs: + out_ads[v] = k + funcs = [out_ads[x] for x in all_ads[:i+1]] + new_lib.append(({"name":n, + "firstthunk":e.virt2rva(othunk)}, + funcs) + ) + all_ads = all_ads[i+1:] + return new_lib + + + +def vm_load_pe(e, align_s = True, load_hdr = True): + aligned = True + for s in e.SHList: + if s.addr & 0xFFF: + aligned = False + break + + if aligned: + if load_hdr: + pe_hdr = e.content[:0x400]+"\x00"*0xc00 + to_c_helper.vm_add_memory_page(e.NThdr.ImageBase, to_c_helper.PAGE_READ|to_c_helper.PAGE_WRITE, pe_hdr) + + if align_s: + for i, s in enumerate(e.SHList[:-1]): + s.size = e.SHList[i+1].addr - s.addr + s.rawsize = s.size + s.offset = s.addr + s = e.SHList[-1] + s.size = (s.size+0xfff)&0xfffff000 + + for s in e.SHList: + data = str(s.data) + data += "\x00"*(s.size-len(data)) + to_c_helper.vm_add_memory_page(e.rva2virt(s.addr), to_c_helper.PAGE_READ|to_c_helper.PAGE_WRITE, data) + s.offset = s.addr + return + + #not aligned + print 'WARNING pe is not aligned, creating big section' + min_addr = None + max_addr = None + data = "" + + if load_hdr: + data = e.content[:0x400] + data += (e.SHList[0].addr - len(data))*"\x00" + min_addr = 0 + + + + for i, s in enumerate(e.SHList): + if i < len(e.SHList)-1: + s.size = e.SHList[i+1].addr - s.addr + s.rawsize = s.size + s.offset = s.addr + + if min_addr == None or s.addr < min_addr: + min_addr = s.addr + + if max_addr == None or s.addr + s.size > max_addr: + max_addr = s.addr + s.size + min_addr = e.rva2virt(min_addr) + max_addr = e.rva2virt(max_addr) + + print hex(min_addr) , hex(max_addr), hex(max_addr - min_addr) + for s in e.SHList: + data += str(s.data) + data += "\x00"*(s.size-len(str(s.data))) + + vm_add_memory_page(min_addr, PAGE_READ|PAGE_WRITE, data) + + + +def vm_load_elf(e, align_s = True, load_hdr = True): + for p in e.ph.phlist: + if p.ph.type != 1: + continue + print hex(p.ph.vaddr), hex(p.ph.offset), hex(p.ph.filesz) + data = e._content[p.ph.offset:p.ph.offset + p.ph.filesz] + + r_vaddr = p.ph.vaddr & ~0xFFF + data = (p.ph.vaddr - r_vaddr) *"\x00" + data + data += (((len(data) +0xFFF) & ~0xFFF)-len(data)) * "\x00" + to_c_helper.vm_add_memory_page(r_vaddr, to_c_helper.PAGE_READ|to_c_helper.PAGE_WRITE, data) + +def preload_lib(e, patch_vm_imp = True, lib_base_ad = 0x77700000): + runtime_lib = libimp(lib_base_ad) + fa = get_import_address(e) + + dyn_funcs = {} + + print 'imported funcs:', fa + for (libname, libfunc), ad in fa.items(): + ad_base_lib = runtime_lib.lib_get_add_base(libname) + ad_libfunc = runtime_lib.lib_get_add_func(ad_base_lib, libfunc, ad) + + libname_s = canon_libname_libfunc(libname, libfunc) + dyn_funcs[libname_s] = ad_libfunc + if patch_vm_imp: + to_c_helper.vm_set_mem(ad, struct.pack('L', ad_libfunc)) + + return runtime_lib, dyn_funcs + +def preload_elf(e, patch_vm_imp = True, lib_base_ad = 0x77700000): + # XXX quick hack + fa = get_import_address_elf(e) + runtime_lib = libimp(lib_base_ad) + + dyn_funcs = {} + + print 'imported funcs:', fa + for (libname, libfunc), ad in fa.items(): + ad_base_lib = runtime_lib.lib_get_add_base(libname) + ad_libfunc = runtime_lib.lib_get_add_func(ad_base_lib, libfunc, ad) + + libname_s = canon_libname_libfunc(libname, libfunc) + dyn_funcs[libname_s] = ad_libfunc + if patch_vm_imp: + to_c_helper.vm_set_mem(ad, struct.pack('L', ad_libfunc)) + + return runtime_lib, dyn_funcs + + +def get_export_name_addr_list(e): + out = [] + for i, n in enumerate(e.DirExport.f_names): + addr = e.DirExport.f_address[e.DirExport.f_nameordinals[i].ordinal] + f_name = n.name.name + out.append((f_name, e.rva2virt(addr.rva))) + return out + + + +class find_call_xref: + def __init__(self, e, off): + import re + self.e = e + self.off = off + #create itertor to find simple CALL offsets + p = re.escape("\xE8") + self.my_iter = re.finditer(p, e.content) + def next(self): + while True: + off_i = self.my_iter.next().start() + off = off_i + 5 + struct.unpack('l', self.e.content[off_i+1:off_i+5])[0] + if off == self.off: + return off_i + raise StopIteration + def __iter__(self): + return self + diff --git a/miasm/tools/seh_helper.py b/miasm/tools/seh_helper.py new file mode 100644 index 00000000..c5d8db44 --- /dev/null +++ b/miasm/tools/seh_helper.py @@ -0,0 +1,348 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +#from codenat import * +from to_c_helper import * +import to_c_helper + +FS_0_AD = 0x7ff70000 +PEB_AD = 0x11110000 + +# fs:[0] Page (TIB) +tib_address = FS_0_AD +peb_address = PEB_AD +peb_ldr_data_address = PEB_AD + 0x1000 +in_load_order_module_list_address = PEB_AD + 0x2000 +in_load_order_module_1 = PEB_AD + 0x3000 +default_seh = PEB_AD + 0x10000 + + +context_address = 0xdeada000 +exception_record_address = 0xdeadb000 +return_from_exception = 0x6eadbeef + +FAKE_SEH_B_AD = 0x11bb0000 + +cur_seh_ad = FAKE_SEH_B_AD +default_image_base = 0x400000 + + +def build_fake_teb(): + """ + +0x000 NtTib : _NT_TIB + +0x01c EnvironmentPointer : Ptr32 Void + +0x020 ClientId : _CLIENT_ID + +0x028 ActiveRpcHandle : Ptr32 Void + +0x02c ThreadLocalStoragePointer : Ptr32 Void + +0x030 ProcessEnvironmentBlock : Ptr32 _PEB + ... + """ + o = "" + o += pdw(default_seh) + o += (0x18 - len(o)) *"\x00" + o += pdw(tib_address) + + o += (0x30 - len(o)) *"\x00" + o += pdw(peb_address) + + return o + + +def build_fake_peb(): + """ + +0x000 InheritedAddressSpace : UChar + +0x001 ReadImageFileExecOptions : UChar + +0x002 BeingDebugged : UChar + +0x003 SpareBool : UChar + +0x004 Mutant : Ptr32 Void + +0x008 ImageBaseAddress : Ptr32 Void + +0x00c Ldr : Ptr32 _PEB_LDR_DATA + """ + o = "" + o += "\x00"*0x8 + o += pdw(default_image_base) + o += pdw(peb_ldr_data_address) + return o + + +def build_fake_ldr_data(): + """ + +0x000 Length : Uint4B + +0x004 Initialized : UChar + +0x008 SsHandle : Ptr32 Void + +0x00c InLoadOrderModuleList : _LIST_ENTRY + +0x014 InMemoryOrderModuleList : _LIST_ENTRY + """ + o = "" + o += "\x00"*0xc + #text XXX + o += pdw(in_load_order_module_list_address) + pdw(0) + o += pdw(in_load_order_module_list_address+8) + pdw(0) + o += pdw(in_load_order_module_list_address+0x10) + pdw(0) + return o + + +def build_fake_inordermodule(modules_name): + """ + +0x000 Flink : Ptr32 -+ This distance + +0x004 Blink : Ptr32 | is eight bytes + +0x018 DllBase : Ptr32 Void -+ DllBase -> _IMAGE_DOS_HEADER + +0x01c EntryPoint : Ptr32 Void + +0x020 SizeOfImage : Uint4B + +0x024 FullDllName : _UNICODE_STRING + +0x02c BaseDllName : _UNICODE_STRING + +0x034 Flags : Uint4B + +0x038 LoadCount : Uint2B + +0x03a TlsIndex : Uint2B + +0x03c HashLinks : _LIST_ENTRY + +0x03c SectionPointer : Ptr32 Void + +0x040 CheckSum : Uint4B + +0x044 TimeDateStamp : Uint4B + +0x044 LoadedImports : Ptr32 Void + +0x048 EntryPointActivationContext : Ptr32 Void + +0x04c PatchInformation : Ptr32 Void + """ + + o = "" + o += pdw(in_load_order_module_1 ) + o += pdw(0) + o += pdw(in_load_order_module_1+8 ) + o += pdw(0) + o += pdw(in_load_order_module_1+0x10) + o += pdw(0) + o += pdw(default_image_base) + o += (0x1000 - len(o))*"I" + + for i, m in enumerate(modules_name): + #fname = os.path.join('win_dll', m) + fname = m + e = pe_init.PE(open(fname, 'rb').read()) + m_o = "" + m_o += pdw(in_load_order_module_1 + (i+1)*0x1000 ) + m_o += pdw(in_load_order_module_1 + (i-1)*0x1000) + m_o += pdw(in_load_order_module_1 + (i+1)*0x1000 + 8 ) + m_o += pdw(in_load_order_module_1 + (i-1)*0x1000 + 8) + m_o += pdw(in_load_order_module_1 + (i+1)*0x1000 + 0x10 ) + m_o += pdw(in_load_order_module_1 + (i-1)*0x1000 + 0x10) + m_o += pdw(e.NThdr.ImageBase) + m_o += pdw(e.rva2virt(e.Opthdr.AddressOfEntryPoint)) + m_o += pdw(e.NThdr.sizeofimage) + m_o += (0x1000 - len(m_o))*"J" + + print "module", "%.8X"%e.NThdr.ImageBase, fname + + o += m_o + return o + + + +all_seh_ad = dict([(x, None) for x in xrange(FAKE_SEH_B_AD, FAKE_SEH_B_AD+0x1000, 0x20)]) +#http://blog.fireeye.com/research/2010/08/download_exec_notes.html +def init_seh(): + global seh_count + seh_count = 0 + + #vm_add_memory_page(tib_address, PAGE_READ | PAGE_WRITE, p(default_seh) + p(0) * 11 + p(peb_address)) + vm_add_memory_page(FS_0_AD, PAGE_READ | PAGE_WRITE, build_fake_teb()) + #vm_add_memory_page(peb_address, PAGE_READ | PAGE_WRITE, p(0) * 3 + p(peb_ldr_data_address)) + vm_add_memory_page(peb_address, PAGE_READ | PAGE_WRITE, build_fake_peb()) + #vm_add_memory_page(peb_ldr_data_address, PAGE_READ | PAGE_WRITE, p(0) * 3 + p(in_load_order_module_list_address) + p(0) * 0x20) + vm_add_memory_page(peb_ldr_data_address, PAGE_READ | PAGE_WRITE, build_fake_ldr_data()) + + #vm_add_memory_page(in_load_order_module_list_address, PAGE_READ | PAGE_WRITE, p(0) * 40) + vm_add_memory_page(in_load_order_module_list_address, PAGE_READ | PAGE_WRITE, build_fake_inordermodule(["win_dll/kernel32.dll", "win_dll/kernel32.dll"])) + vm_add_memory_page(default_seh, PAGE_READ | PAGE_WRITE, p(0xffffffff) + p(0x41414141) + p(0x42424242)) + + vm_add_memory_page(context_address, PAGE_READ | PAGE_WRITE, '\x00' * 0x2cc) + vm_add_memory_page(exception_record_address, PAGE_READ | PAGE_WRITE, '\x00' * 200) + + vm_add_memory_page(FAKE_SEH_B_AD, PAGE_READ | PAGE_WRITE, 0x10000*"\x00") + +#http://www.codeproject.com/KB/system/inject2exe.aspx#RestorethefirstRegistersContext5_1 +def regs2ctxt(regs): + ctxt = "" + ctxt += '\x00\x00\x00\x00' #ContextFlags + ctxt += '\x00\x00\x00\x00' * 6 #drX + ctxt += '\x00' * 112 #float context + ctxt += '\x00\x00\x00\x00' + '\x3b\x00\x00\x00' + '\x23\x00\x00\x00' + '\x23\x00\x00\x00' #segment selectors + ctxt += p(regs['edi']) + p(regs['esi']) + p(regs['ebx']) + p(regs['edx']) + p(regs['ecx']) + p(regs['eax']) + p(regs['ebp']) + p(regs['eip']) #gpregs + ctxt += '\x23\x00\x00\x00' #cs + ctxt += '\x00\x00\x00\x00' #eflags + ctxt += p(regs['esp']) #esp + ctxt += '\x23\x00\x00\x00' #ss segment selector + return ctxt + + +def ctxt2regs(ctxt): + ctxt = ctxt[:] + regs = {} + #regs['ctxtsflags'] = updw(ctxt[:4]) + ctxt = ctxt[4:] + for i in xrange(8): + if i in [4, 5]: + continue + #regs['dr%d'%i] = updw(ctxt[:4]) + ctxt = ctxt[4:] + + ctxt = ctxt[112:] #skip float + + #regs['seg_gs'] = updw(ctxt[:4]) + ctxt = ctxt[4:] + #regs['seg_fs'] = updw(ctxt[:4]) + ctxt = ctxt[4:] + #regs['seg_es'] = updw(ctxt[:4]) + ctxt = ctxt[4:] + #regs['seg_ds'] = updw(ctxt[:4]) + ctxt = ctxt[4:] + + regs['edi'], regs['esi'], regs['ebx'], regs['edx'], regs['ecx'], regs['eax'], regs['ebp'], regs['eip'] = struct.unpack('LLLLLLLL', ctxt[:4*8]) + ctxt = ctxt[4*8:] + + #regs['seg_cs'] = updw(ctxt[:4]) + ctxt = ctxt[4:] + + #regs['eflag'] = updw(ctxt[:4]) + ctxt = ctxt[4:] + + regs['esp'] = updw(ctxt[:4]) + ctxt = ctxt[4:] + + for a, b in regs.items(): + print a, hex(b) + #skip extended + return regs + + +def get_free_seh_place(): + global all_seh_ad + ads = all_seh_ad.keys() + ads.sort() + for ad in ads: + v = all_seh_ad[ad] + if v == None: + print 'TAKING SEH', hex(ad) + all_seh_ad[ad] = True + return ad + raise ValueError('too many stacked seh ') + +def free_seh_place(ad): + print 'RELEASING SEH', hex(ad) + + if not ad in all_seh_ad: + raise ValueError('zarb seh ad!', hex(ad)) + if all_seh_ad[ad] != True: + raise ValueError('seh alreaedy remouvede?!!', hex(ad)) + all_seh_ad[ad] = None + +def fake_seh_handler(except_code): + global seh_count + regs = vm_get_gpreg() + print '-> exception at', hex(regs['eip']), seh_count + seh_count += 1 + + # Help lambda + p = lambda s: struct.pack('L', s) + + dump_gpregs_py() + # Forge a CONTEXT + ctxt = '\x00\x00\x00\x00' + '\x00\x00\x00\x00' * 6 + '\x00' * 112 + '\x00\x00\x00\x00' + '\x3b\x00\x00\x00' + '\x23\x00\x00\x00' + '\x23\x00\x00\x00' + p(regs['edi']) + p(regs['esi']) + p(regs['ebx']) + p(regs['edx']) + p(regs['ecx']) + p(regs['eax']) + p(regs['ebp']) + p(regs['eip']) + '\x23\x00\x00\x00' + '\x00\x00\x00\x00' + p(regs['esp']) + '\x23\x00\x00\x00' + #ctxt = regs2ctxt(regs) + + # Find a room for seh + #seh = (get_memory_page_max_address_py()+0x1000)&0xfffff000 + + # Get current seh (fs:[0]) + seh_ptr = vm_read_dword(tib_address) + + # Retrieve seh fields + old_seh, eh, safe_place = struct.unpack('LLL', vm_get_str(seh_ptr, 0xc)) + + print '-> seh_ptr', hex(seh_ptr), '-> { old_seh', hex(old_seh), 'eh', hex(eh), 'safe_place', hex(safe_place), '}' + #print '-> write SEH at', hex(seh&0xffffffff) + + # Write current seh + #vm_add_memory_page(seh, PAGE_READ | PAGE_WRITE, p(old_seh) + p(eh) + p(safe_place) + p(0x99999999)) + + # Write context + vm_set_mem(context_address, ctxt) + + # Write exception_record + + """ + #http://msdn.microsoft.com/en-us/library/aa363082(v=vs.85).aspx + + typedef struct _EXCEPTION_RECORD { + DWORD ExceptionCode; + DWORD ExceptionFlags; + struct _EXCEPTION_RECORD *ExceptionRecord; + PVOID ExceptionAddress; + DWORD NumberParameters; + ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } EXCEPTION_RECORD, *PEXCEPTION_RECORD; + """ + + vm_set_mem(exception_record_address, p(except_code) + p(0) + p(0) + p(regs['eip']) + p(0) + p(0) ) + + # Prepare the stack + vm_push_uint32_t(context_address) # Context + vm_push_uint32_t(seh_ptr) # SEH + vm_push_uint32_t(exception_record_address) # ExceptRecords + vm_push_uint32_t(return_from_exception) # Ret address + + + + # Set fake new current seh for exception + + fake_seh_ad = get_free_seh_place() + print hex(fake_seh_ad) + vm_set_mem(fake_seh_ad, p(seh_ptr) + p(0xaaaaaaaa) + p(0xaaaaaabb) + p(0xaaaaaacc)) + vm_set_mem(tib_address, p(fake_seh_ad)) + + dump_seh() + + print '-> jumping at', hex(eh) + to_c_helper.vm_reset_exception() + + + regs = vm_get_gpreg() + #XXX set ebx to nul? + regs['ebx'] = 0 + vm_set_gpreg(regs) + + return eh + +fake_seh_handler.base = FAKE_SEH_B_AD + + +def dump_seh(): + print 'dump_seh:' + print '-> tib_address:', hex(tib_address) + + cur_seh_ptr = vm_read_dword(tib_address) + + indent = 1 + loop = 0 + while True: + #if loop > 3: + # djawidj + prev_seh, eh = struct.unpack('LL', vm_get_str(cur_seh_ptr, 8)) + print '\t' * indent + 'seh_ptr:', hex(cur_seh_ptr), ' -> { prev_seh:', hex(prev_seh), 'eh:', hex(eh), '}' + if prev_seh in [0xFFFFFFFF, 0]: + break + cur_seh_ptr = prev_seh + indent += 1 + loop += 1 diff --git a/miasm/tools/to_c_helper.py b/miasm/tools/to_c_helper.py new file mode 100644 index 00000000..28ed91e2 --- /dev/null +++ b/miasm/tools/to_c_helper.py @@ -0,0 +1,1024 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from miasm.core import asmbloc +from miasm.core.bin_stream import bin_stream +from miasm.arch.ia32_arch import * +from miasm.arch.ia32_sem import * +import struct + +from elfesteem import * + + + +from miasm.tools.emul_helper import * +from miasm.expression.expression_eval_abstract import eval_abs +from miasm.expression.expression_helper import * + +from elfesteem.strpatchwork import StrPatchwork +import ctypes + +def id2new(i): + return str(i)+'_new' + + + + +my_C_id = [ + eax, + ebx, + ecx, + edx, + esi, + edi, + esp, + ebp, + eip, + zf, + nf, + pf, + of, + cf, + af, + df, + #eax_new, + #ebx_new, + #ecx_new, + #edx_new, + #esi_new, + #edi_new, + #esp_new, + #ebp_new, + #eip_new, + #zf_new, + #nf_new, + #pf_new, + #of_new, + #cf_new, + #af_new, + #df_new, + tf, + i_f, + iopl, + nt, + rf, + vm, + ac, + vif, + vip, + i_d, + #tf_new, + #i_f_new, + #iopl_new, + #nt_new, + #rf_new, + #vm_new, + #ac_new, + #vif_new, + #vip_new, + #i_d_new, + #my_tick, + reg_float_control, + cond, + ds, + #vm_exception_flags, + #vm_exception_flags_new, + #vm_last_write_ad, + #vm_last_write_size, + tsc1, + tsc2, + + float_st0, + float_st1, + float_st2, + float_st3, + float_st4, + float_st5, + float_st6, + float_st7, + + float_c0, + float_c1, + float_c2, + float_c3, + + cr0, + cr3, + + + float_stack_ptr, + + ] +id2Cid = {} +for x in my_C_id: + id2Cid[x] = ExprId('vmcpu.'+str(x)) + +def patch_c_id(e): + return e.reload_expr(id2Cid) + + +code_deal_exception_at_instr = r""" +if (vmcpu.vm_exception_flags > EXCEPT_NUM_UDPT_EIP) { + %s = 0x%X; + return (unsigned int)vmcpu.eip; +} +""" +code_deal_exception_post_instr = r""" +if (vmcpu.vm_exception_flags) { + %s = (vmcpu.vm_exception_flags > EXCEPT_NUM_UDPT_EIP) ? 0x%X : 0x%X; + return (unsigned int)vmcpu.eip; +} +""" + + +def Exp2C(exprs, l = None, addr2label = None, gen_exception_code = False): + if not addr2label: + addr2label = lambda x:x + id_to_update = [] + out = [] + out_eip = [] + #print [str(x) for x in exprs] + + dst_dict = {} + + new_expr = [] + + eip_is_dst = False + + for e in exprs: + if not isinstance(e, ExprAff): + raise ValueError('should be expr', str(e)) + + if isinstance(e.dst, ExprId): + if not e.dst in dst_dict: + dst_dict[e.dst] = [] + dst_dict[e.dst].append(e) + else: + new_expr.append(e) + + for dst, exs in dst_dict.items(): + if len(exs) ==1: + new_expr += exs + continue + print 'warning: detected multi dst to same id' + print l + new_expr+=exs + #test if multi slice (for example xchg al, ah) + if not False in [isinstance(e.src, ExprCompose) for e in exs]: + #spotted multi affectation to same id + e_colision = reduce(lambda x,y:x+y, [e.get_modified_slice() for e in exs]) + #print [str(x) for x in e_colision] + known_intervals = [(x.start, x.stop) for x in e_colision] + #print known_intervals + missing_i = get_missing_interval(known_intervals) + #print missing_i + + rest = [ExprSliceTo(ExprSlice(dst, *r), *r) for r in missing_i] + final_dst = ExprCompose(e_colision+ rest) + + new_expr.append(ExprAff(dst, final_dst)) + + out_mem = [] + + for e in new_expr: + + if True:#e.dst != eip: + + src, dst = e.src, e.dst + str_src = patch_c_id(src).toC() + str_dst = patch_c_id(dst).toC() + if isinstance(dst, ExprId): + id_to_update.append(dst) + str_dst = id2new(patch_c_id(dst)) + out.append('%s = %s;'%(str_dst, str_src)) + elif isinstance(dst, ExprMem): + str_dst = str_dst.replace('MEM_LOOKUP', 'MEM_WRITE') + out_mem.append('%s, %s);'%(str_dst[:-1], str_src)) + + + if e.dst == eip : + eip_is_dst = True + if isinstance(e.src, ExprCond): + #out_eip.append("cond = %s;"%e.src.cond.toC()) + out.append("vmcpu.cond = %s;"%patch_c_id(e.src.cond).toC()) + out_eip+=["if (vmcpu.cond)", + "\tGOTO_STATIC(vmcpu.eip);//%s);"%(addr2label(e.src.src1.arg)), + "else", + "\tGOTO_STATIC(vmcpu.eip);//%s);"%(addr2label(e.src.src2.arg)), + ] + else: + if isinstance(e.src, ExprInt): + if l.is_subcall(): + out_eip.append("GOTO_STATIC_SUB(%s);"%(addr2label(e.src.arg))) + else: + out_eip.append("GOTO_STATIC(0x%.8X);"%(e.src.arg)) + else: + if l.is_subcall(): + out_eip.append("GOTO_DYN_SUB(%s);"%(patch_c_id(e.src).toC())) + else: + out_eip.append('GOTO_DYNAMIC; //(%s);'%patch_c_id(e.src).toC()) + + + #if len(id_to_update) != len(set(id_to_update)): + # raise ValueError('Not implemented: multi dst to same id!', str([str(x) for x in exprs])) + + out+=out_mem + + if gen_exception_code: + out.append(code_deal_exception_at_instr % (patch_c_id(eip), l.offset)) + + for i in id_to_update: + out.append('%s = %s;'%(patch_c_id(i), id2new(patch_c_id(i)))) + + + + + post_instr = [] + #### test stop exec #### + if gen_exception_code: + if eip_is_dst: + #post_instr.append("if (vmcpu.vm_exception_flags) { /*eip = 0x%X; */return (unsigned int)vm_get_exception(vmcpu.vm_exception_flags); }"%(l.offset)) + post_instr.append("if (vmcpu.vm_exception_flags) { /*eip = 0x%X; */return (unsigned int)vmcpu.eip; }"%(l.offset)) + else: + post_instr.append(code_deal_exception_post_instr % (patch_c_id(eip), l.offset, l.offset + l.l)) + + """ + print "1" + print out + print "2" + print out_eip + print "3" + print post_instr + """ + + + + #eip manip after all modifications + return out+out_eip, post_instr + + +def bloc2C(all_bloc, addr2label = None, gen_exception_code = False, dbg_instr = False, dbg_reg = False, dbg_lbl = False, filtered_ad = None, tick_dbg = None): + all_instrs = digest_allbloc_instr(all_bloc) + + if not addr2label: + addr2label = lambda x:"loc_%.8X"%x + + + out = [] + label_done = set() + for b in all_bloc: + #out.append("%s:"%str(b.label.name)) + if dbg_lbl or dbg_instr: + if (not filtered_ad) or b.label.offset in filtered_ad: + if tick_dbg!=None: + out.append('if (my_tick > %d)'%tick_dbg) + out.append(r'printf("%s\n");'%str(b.label.name)) + + + for l in b.lines: + if l.offset in label_done: + continue + label_done.add(l.offset) + l,ex = all_instrs[l.offset] + if addr2label: + out.append("%s:"%addr2label(l.offset)) + else: + out.append("loc_%.8X:"%l.offset) + + o, post_instr = Exp2C(ex, l, addr2label, gen_exception_code) + + + + + #if add_return: + # o.append('return;'); + #if add_call: + # o.append('%s();'%add_call); + + if (0xF2 in l.prefix or 0xF3 in l.prefix) and l.m.name in ["ins", "outs", "movsb", "movsw", "movsd", "lodsb", "lodsw", "lodsd", "stosb", "stosw", "stosd" ]+ [ "cmpsb", "cmpsw", "cmpsd", "scasb", "scasw", "scasd" ]: + zf_w = zf in reduce(lambda x,y:x+y, [list(x.get_w()) for x in ex], []) + my_o = ["while (1){"] + #my_o.append("if (vmcpu.vm_exception_flags) { %s = 0x%X; return (PyObject*)vm_get_exception(vm_exception_flags); }"%(patch_c_id(eip), l.offset)) + #my_o.append(code_deal_exception_post_instr % (patch_c_id(eip), l.offset, l.offset + l.l)) + my_o.append(code_deal_exception_post_instr % (patch_c_id(eip), l.offset, l.offset)) + + + #my_o.append(r'printf("ecx %.8X\n", ecx );') + my_o+= ['if (%s==0) break;'%patch_c_id(ecx)] + my_o+=o + my_o+= ['%s--;'%patch_c_id(ecx)] + if zf_w: + if 0xF3 in l.prefix: + my_o+= ['if (%s==0) break;'%patch_c_id(zf)] + if 0xF2 in l.prefix: + my_o+= ['if (%s==1) break;'%patch_c_id(zf)] + + + my_o += ["}"] + + o = my_o + + o+= post_instr + #print "\t"+"\n\t".join(o) + + if dbg_reg and ((not filtered_ad) or l.offset in filtered_ad): + if tick_dbg!=None: + out.append(r'vmcpu.my_tick++;') + out.append('if (vmcpu.my_tick > %d)'%tick_dbg) + out.append(r'printf(" eax %.8X ebx %.8X ecx %.8X edx %.8X esi %.8X edi %.8X esp %.8X ebp %.8X c%X p%X a%X z%X n%X d%X o%X\n", vmcpu.eax, vmcpu.ebx, vmcpu.ecx, vmcpu.edx, vmcpu.esi, vmcpu.edi, vmcpu.esp, vmcpu.ebp, vmcpu.cf, vmcpu.pf, vmcpu.af, vmcpu.zf, vmcpu.nf, vmcpu.df, vmcpu.of );') + if dbg_instr and ((not filtered_ad) or l.offset in filtered_ad): + if tick_dbg!=None: + out.append('if (vmcpu.my_tick > %d)'%tick_dbg) + out.append(r'printf("%s\n");'%str(l)) + else: + out.append(r'//%s'%str(l)) + + out+=o + + + for c in b.bto: + if c.c_t == asmbloc.asm_constraint.c_next: + out.append("GOTO_STATIC(0x%.8X);"%(c.label.offset)) + + """ + #in case of bad disasm, no next, so default next instr + #XXX BUG if no line!!! + + if b.lines: + l = b.lines[-1] + out.append("GOTO_STATIC(%s);"%(addr2label(l.offset + l.l))) + """ + + + return out + + + +def bloc_gen_C_func(all_bloc, funcname, addr2label = None, gen_exception_code = False, dbg_instr = False, dbg_reg = False, dbg_lbl = False, filtered_ad = None, tick_dbg = None): + f_dec = 'unsigned int %s(void)'%funcname + out = [] + out+=[f_dec, + '{', + ] + out += bloc2C(all_bloc, addr2label, gen_exception_code, dbg_instr, dbg_reg, dbg_lbl, filtered_ad, tick_dbg) + out+=['}', + ] + return f_dec, out + + + + +def gen_x86_core(): + import os + + lib_dir = os.path.dirname(os.path.realpath(__file__)) + lib_dir = os.path.join(lib_dir, 'emul_lib') + + txt = "" + txt += '#include "%s/queue.h"\n'%lib_dir + txt += '#include "%s/libcodenat.h"\n'%lib_dir + + txt += r''' + +//#define RAISE(errtype,msg) { PyErr_SetString(errtype,msg); RE_RAISE; } +//#define RE_RAISE { return NULL; } + +#define RAISE(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return p;} + + + +''' + return txt + + +def gen_C_source(funcs_code, known_mems, dyn_dispatcher): + c_source = dyn_dispatcher + c_source+= "\n".join(funcs_code) + + kmems = gen_known_mems_code(known_mems) + c_source = gen_x86_core()+"\n".join(kmems)+c_source + return c_source + + +def blocs_to_memory_ranges(all_blocs): + code_addr = [] + for b in all_blocs: + # XXX no lines in bloc? + if not b.lines: + continue + code_addr.append((b.lines[0].offset, b.lines[-1].offset + b.lines[-1].l)) + return code_addr + +def del_bloc_in_range(all_blocs, ad1, ad2): + bloc_out = [] + for b in all_blocs: + # XXX no lines in bloc? + if not b.lines: + continue + + if b.lines[0].offset>=ad2 or b.lines[-1].offset + b.lines[-1].l <= ad1: + bloc_out.append(b) + else: + #print 'inv bloc', b.label + pass + return bloc_out + +def merge_memory_ranges(t): + i = 0 + while i < len(t)-1: + j = i+1 + rA1, rA2 = t[i] + while j < len(t): + rB1, rB2 = t[j] + #print "uu", hex(rA1), hex(rA2) + #print "vv", hex(rB1), hex(rB2) + + if rA1 >= rB1 and rA2 <= rB2: + #print '#rA included in rB' + rA1, rA2 = t[j] + del(t[j]) + continue + elif rA1 <= rB1 and rA2 >= rB2: + #print '#rB included in rA' + del(t[j]) + continue + elif rA1 <= rB1 and rA2 >= rB1: + #print '#rA ends in rB' + rA2 = rB2 + del(t[j]) + continue + elif rB1 <= rA1 and rB2 >= rA1: + #print '#rB ends in rA' + rA1 = rB1 + del(t[j]) + continue + j+=1 + if t[i] != (rA1, rA2): + t[i] = rA1, rA2 + else: + i+=1 + + +def gen_code_addr_tab(t): + out = [] + + out += ["#define CODE_ADDR_SIZE (2*%d)"%len(t)] + out += ["unsigned int code_addr_tab[2*%d] = {"%len(t)] + for r in t: + out += ["\t0x%.8X, 0x%.8X,"%(r)] + + out += ['};'] + return '\n'.join(out)+'\n' + +def asm2C(f_name, known_mems, dyn_func, in_str, x86_mn, symbol_pool, func_to_dis, dont_dis = [], follow_call = False, dontdis_retcall = False, log_mn = False, log_reg = False, log_lbl = False, filtered_ad = [], tick_dbg = None, code_addr = [], all_bloc_funcs = []): + + funcs_code = [] + funcs_dec = [] + + all_bloc_funcs+=asmbloc.dis_multi_func(in_str, x86_mn, symbol_pool, func_to_dis, dont_dis, follow_call, dontdis_retcall) + """ + for f in all_bloc_funcs: + print hex(f) + print all_bloc_funcs[f] + g = asmbloc.bloc2graph(all_bloc_funcs[f]) + open("tmp/graph_%.8X.txt"%f , "w").write(g) + """ + + #fds + + + for b in all_bloc_funcs: + if b.label.offset in dont_dis: + continue + + #XXX no lines in bloc? + if not b.lines: + continue + l = b.lines[-1] + #if l.m.name.startswith('jmp') and not x86_afs.symb in l.arg[0]: + # raise ValueError('unsupported dst', str(l)) + ''' + if (l.m.name.startswith('call') or l.m.name.startswith('jmp')) and not x86_afs.symb in l.arg[0]: + + #print "TOTO", hex(l.offset), l, l.arg[0] + + #deal dyn call + instr = x86_mn.dis(x86_mn.asm('mov eax, eax')[0]) + #XXX HACK to be unik address + instr.offset = l.offset+1 + + instr.arg = [{x86_afs.symb:{ExprId('dyn_dst'):1}}, dict(l.arg[0])] + + #print instr, str(instr) + #instr.offset = 0x1337beef + + #b.lines[-1:-1] = [instr] + #l.arg[0] = {x86_afs.symb:func_deal_dyn} + + + #if dyn func is not in ref, add it (todo in gen C) + ''' + + for l in b.lines: + + #test imm redirect mem ad + for a in l.arg: + if not x86_afs.imm in a: continue + i = a[x86_afs.imm] + + + l_name = None + for m_ad, m_val in known_mems.items(): + if m_ad <= i < m_ad+len(m_val): + l_name = "(unsigned int)&tab_%.8X[0x%X]"%(m_ad, i-m_ad) + break + + for f in dyn_func: + if i == f: + if i == 0x00401EDB: + fdsfdsf + #l_name = "(unsigned int)&dyn_func_%.8X"%(f) + l_name = "(unsigned int)0x%.8X"%(f) + for f in func_to_dis: + if i == f: + #l_name = "(unsigned int)&func_%.8X"%(f) + l_name = "(unsigned int)0x%.8X"%(f) + break + + if not l_name: + continue + + + + + label = asmbloc.asm_label(l_name, i) + #symbol_pool.add(label) + a[x86_afs.symb] = {label:1} + del a[x86_afs.imm] + + + + + + + + + + #print "_"*20 + + code_addr += blocs_to_memory_ranges(all_bloc_funcs) + merge_memory_ranges(code_addr) + + + + + #g = asmbloc.bloc2graph(all_bloc) + #open("graph_%.8X.txt"%ad , "w").write(g) + + allb = all_bloc_funcs#reduce(lambda x,y:x+y, all_bloc_funcs.values(), []) + f_dec, out = bloc_gen_C_func(allb, f_name, None, True, log_mn, log_reg, log_lbl, filtered_ad, tick_dbg) + funcs_dec.append(f_dec) + funcs_code+=out + + + for f, f_code in dyn_func.items(): + l_name = "loc_%.8X"%f + funcs_code[-1:-1] = [l_name+":"] + funcs_code[-1:-1] = f_code.split('\n') + l = asmbloc.asm_label(l_name, f) + b = asmbloc.asm_bloc(l) + #all_bloc_funcs[f] = [b] + all_bloc_funcs += [b] + + funcs_code[2:2] = ["FUNC_DYNAMIC;"] + funcs_code[3:3] = ["GOTO_DYNAMIC;"] + + funcs_code[0:0] = [gen_code_addr_tab(code_addr)] + #funcs_dec = ["void func_%.8X(void)"%x for x in all_bloc_funcs] + + + #test return direct dyn dispatch + dispatch_table = dispatch_table_from_f_blocs(all_bloc_funcs) + dyn_dispatcher = gen_dynamic_dispatcher(dispatch_table) + + return funcs_code, dyn_dispatcher + + +def gen_C_from_asmbloc(in_str, offset, symbol_pool, dont_dis = [], job_done = None, log_mn = False, log_reg = False, log_lbl = False, filtered_ad = [], tick_dbg = None, code_addr = [], all_bloc_funcs = []): + if job_done == None: + job_done = set() + + f_name = "bloc_%.8X"%offset + l = symbol_pool.getby_offset_create(offset) + cur_bloc = asmbloc.asm_bloc(l) + + asmbloc.dis_bloc(x86_mn, in_str, cur_bloc, offset, job_done, symbol_pool,[], + follow_call = False, patch_instr_symb = True, dontdis_retcall = False,lines_wd = None, amode=x86_afs.u32, sex=0) + + f_dec, out = bloc_gen_C_func([cur_bloc], f_name, None, True, log_mn, log_reg, log_lbl, filtered_ad, tick_dbg) + #print "\n".join(out) + return f_dec, out, cur_bloc + + + + + +def dispatch_table_from_f_blocs(all_f_b): + dispatch_table = {} + #for b in all_f_b: + # dispatch_table[b.label.offset] = b.label.name + for b in all_f_b: + dispatch_table[b.label.offset] = b.label.name + for l in b.lines: + dispatch_table[l.offset] = "loc_%.8X"%l.offset + + return dispatch_table + + +def gen_dynamic_dispatcher(dispatch_table): + offsets = dispatch_table.keys() + offsets.sort() + + out1 = [] + out1 += ["#define FUNC_DYNAMIC"] + out1 += ['void* tab_eip_label[(%d+1)*2] = '%len(dispatch_table)] + out1 += ['{'] + for o in offsets: + out1+=['\t(void*)0x%.8X, (void*)&&%s,'%(o, dispatch_table[o])] + out1+=['\t(void*)0x%.8X, (void*)0x0,'%(0)] + + out1 += ['};'] + + out2 = [] + out2 += ["void * get_label_from_eip(void** tab_eip_label)"] + out2 += ['{'] + + out2 += ['\tvoid *labelref = NULL;'] + + out2 += ['\tunsigned int i = 0;'] + out2 += ['\twhile (tab_eip_label[2*i]!= NULL && tab_eip_label[2*i+1]!=NULL){'] + out2 += ['\t\tif (tab_eip_label[i*2] == (void*)vmcpu.eip){'] + out2 += ['\t\t\tlabelref = tab_eip_label[i*2+1];'] + out2 += ['\t\t\treturn labelref;'] + out2 += ['\t\t}'] + out2 += ['\ti++;'] + out2 += ['\t}'] + out2 += [r'printf("Unkown destination! 0x%.8X\n", vmcpu.eip);'] + out2 += [r'vmcpu.vm_exception_flags |= EXCEPT_UNK_EIP;'] + #out2 += [r'exit(0);'] + out2 += ['return labelref;'] + out2 += ['}'] + + + out = [] + + out += ["#define GOTO_DYNAMIC"] + out += ["labelref = get_label_from_eip();"] + out += ["if (labelref == NULL) {"] + out += [r'printf("Unkown destination! 0x%.8X\n", vmcpu.eip);'] + out += [r'vmcpu.vm_exception_flags |= EXCEPT_UNK_EIP;'] + out += ["return (PyObject*)vm_get_exception(vm_exception_flags);"] + out += ['}'] + out += ['goto *labelref;'] + + """ + out += ['{'] + #out += [r'printf("search dst: %X\n", eip);'] + + out += ['switch(eip){'] + for o in offsets: + out+=['case 0x%.8X:'%o] + out+=['goto %s;'%dispatch_table[o]] + out+=['break;'] + + out += ['case 0x1337beef:'] + out += [r'printf("return reached %X\n", eip);'] + out += ['return NULL;'] + out += ['default:'] + out += [r'printf("Unkown destination! 0x%.8X\n", eip);'] + out += [r'vm_exception_flags |= EXCEPT_UNK_EIP;'] + out += ["return (PyObject*)vm_get_exception(vm_exception_flags);"] + out += ['break;'] + out += ['}'] + out += ['}'] + """ + return out1, out2 + +def gen_dyn_func_manager(dyn_func, dis_func): + total_func_num = len(dyn_func)+len(dis_func) + out = "int (*tab_func[%d][2])(void) = {"%(total_func_num) + dec_f_ptr = "" + init_f_ptr = "" + for f_ad, f_name in dyn_func.items(): + out+="{%s, %s},"%("0x%.8X"%f_ad, f_name) + + dec_f_ptr += "unsigned int dyn_func_%.8X;\n"%(f_ad) + init_f_ptr+= "dyn_func_%.8X = (unsigned int)&%s;\n"%(f_ad, f_name) + + for f_ad in dis_func: + out+="{0x%.8X, func_%.8X},"%(f_ad, f_ad) + out+="};" + + + code = "\n" + code += "#define DYN_FUNC_NUM %d"%total_func_num + code += r""" +/* +void func_dyn_manager(void) +{ + unsigned int i; +""" + out + r""" + + for (i=0;i<DYN_FUNC_NUM;i++){ + if (dyn_dst == tab_func[i][0]){ + printf("i %d v@%X r@%X\n", i, tab_func[i][0], tab_func[i][1]); + tab_func[i][1](); + return; + } + } + + printf("unknown dyn dst!\n"); + exit(0); +} +*/ + """ + return dec_f_ptr, init_f_ptr, code + + + +def insert_printf(c_source, label): + for i, l in enumerate(c_source): + print l + if l.startswith(label): + c_source[i+1:i+1] = ['printf("reached %s\\n");'%label] + + + + +def gen_label_declaration(known_mems): + lab_dec = [] + + for m_ad, m_val in known_mems.items(): + dec_name = "char tab_%.8X[0x%X]"%(m_ad, len(m_val)) + data = m_val + dec_name+=' = {'+', '.join(["0x%.2X"%ord(x) for x in data])+'};' + lab_dec.append(dec_name) + + + return lab_dec + + +def gen_call_func(funcname, args, precode = "", postcode = ""): + out = "" + +def gen_known_mems_code(known_mems): + code = [] + for m_ad, m_val in known_mems.items(): + out = "" + out += "char *tab_%.8X;"%(m_ad) + out += "char tab_data_%.8X[0x%X] = "%(m_ad, len(m_val)) + out += '{'+', '.join(["0x%.2X"%ord(x) for x in m_val])+'};' + out += 'unsigned int get_tab_%.8X() { return (unsigned int)tab_%.8X;}'%(m_ad, m_ad) + code.append(out) + + #test transform tab_XX to dynamic allocated prod + """ + code.append("void init_tab_mem(void)") + code.append("{") + code.append("unsigned int ret;") + + for m_ad, m_val in known_mems.items(): + #code.append("tab_%.8X = malloc(0x%.8X);\n"%(m_ad, len(m_val))) + code.append("ret = posix_memalign(&tab_%.8X, 0x10000, 0x%.8X);"%(m_ad, len(m_val))) + code.append("if (ret){") + code.append(r' printf("cannot alloc");') + code.append(r' exit(-1);') + code.append(r'}') + + + code.append("memcpy(tab_%.8X, tab_data_%.8X, 0x%.8X);"%(m_ad, m_ad, len(m_val))) + code.append("}\n") + """ + + + + return code + +if __name__ == '__main__': + e = dec(ExprMem(eax)) + for x in e: + print x + print '_'*80 + o = Exp2C(e) + for x in o: + print x + print '#'*80 + + new_e = [x.replace_expr({ExprMem(eax): ExprId('ioio')}) for x in e] + for x in new_e: + print x + print '-'*80 + o = Exp2C(new_e) + for x in o: + print x + print '#'*80 + + + + +def _compile(self): + import os + from distutils.core import setup, Extension + import os + + lib_dir = os.path.dirname(os.path.realpath(__file__)) + lib_dir = os.path.join(lib_dir, 'emul_lib') + + os.chdir(self._buildDir) + ext = Extension(self._moduleName, + [self._srcFileName], + library_dirs=self._options.get('library_dirs'), + libraries=self._options.get('libraries'), + define_macros=self._options.get('define_macros'), + undef_macros=self._options.get('undef_macros'), + extra_link_args = ['-Wl,-rpath,'+lib_dir] + ) + try: + setup(name = self._moduleName, + version = self._moduleVersion, + ext_modules = [ext], + script_args = ["build"] + (self._options.get('distutils_args') or []), + script_name="C.py", + package_dir=self._buildDir, + ) + except SystemExit, e: + raise BuildError(e) + + os.chdir(self._homeDir) + + + + + +from miasm.tools.codenat import * +''' +def updt_bloc_emul(known_blocs, in_str, my_eip, symbol_pool, code_blocs_mem_range, dont_dis = [], log_mn = False, log_regs = False): + + f_dec, funcs_code, cur_bloc = gen_C_from_asmbloc(in_str, my_eip, symbol_pool, dont_dis, log_mn, log_regs) + + dyn_dispatcher = """ + #define GOTO_DYNAMIC do {return %s;} while(0) + #define GOTO_STATIC(a) do {vmcpu.eip = a;return %s;} while(0) + #define GOTO_STATIC_SUB(a) do {return %s;} while(0) + #define GOTO_DYN_SUB(a) do {return %s;} while(0) + #define vm_get_exception(a) %s + """%(patch_c_id(eip), patch_c_id(eip), patch_c_id(eip), patch_c_id(eip), patch_c_id(eip)) + + c_source = gen_C_source(funcs_code, {}, dyn_dispatcher) + c_source = "#include <Python.h>\n"+c_source + + a = gen_C_module(c_source) + bn = bloc_nat(my_eip, cur_bloc, a, log_mn, log_regs) + #f_dec = f_dec[10:-6] + f_dec = f_dec[13:-6] + a.func = a[f_dec] + known_blocs[my_eip] = bn + + ###### update code ranges ### + + code_addr = blocs_to_memory_ranges([bn.b]) + code_blocs_mem_range += code_addr + merge_memory_ranges(code_blocs_mem_range) + reset_code_bloc_pool_py() + for a, b in code_blocs_mem_range: + vm_add_code_bloc(a, b) +''' + +ttt = 0 +def updt_bloc_emul(known_blocs, in_str, my_eip, symbol_pool, code_blocs_mem_range, dont_dis = [], job_done = None, log_mn = False, log_regs = False): + if job_done == None: + job_done = set() + f_dec, funcs_code, cur_bloc = gen_C_from_asmbloc(in_str, my_eip, symbol_pool, dont_dis, job_done, log_mn, log_regs) + + dyn_dispatcher = """ + #define GOTO_DYNAMIC do {return %s;} while(0) + #define GOTO_STATIC(a) do {vmcpu.eip = a; return %s;} while(0) + #define GOTO_STATIC_SUB(a) do {return %s;} while(0) + #define GOTO_DYN_SUB(a) do {return %s;} while(0) + #define vm_get_exception(a) %s + """%(patch_c_id(eip), patch_c_id(eip), patch_c_id(eip), patch_c_id(eip), patch_c_id(eip)) + + c_source = gen_C_source(funcs_code, {}, dyn_dispatcher) + c_source = "#include <Python.h>\n"+c_source + #c_source = '#include "emul_lib/libcodenat.h"\n'+c_source + #print c_source + + a = gen_C_module_tcc(f_dec[13:-6], c_source) + bn = bloc_nat(my_eip, cur_bloc, a, log_mn, log_regs) + + bn.c_source = c_source + #f_dec = f_dec[10:-6] + f_dec = f_dec[13:-6] + #a.func = a[f_dec] + known_blocs[my_eip] = bn + ###### update code ranges ### + code_addr = blocs_to_memory_ranges([bn.b]) + code_blocs_mem_range += code_addr + merge_memory_ranges(code_blocs_mem_range) + reset_code_bloc_pool_py() + for a, b in code_blocs_mem_range: + vm_add_code_bloc(a, b) + +#''' + +def updt_pe_from_emul(e): + for s in e.SHList: + sdata = vm_get_str(e.rva2virt(s.addr), s.rawsize) + e.virt[e.rva2virt(s.addr)] = sdata + return bin_stream(e.virt) + + return bin_stream_vm() + + + +def updt_automod_code(known_blocs): + w_ad, w_size = vm_get_last_write_ad(), vm_get_last_write_size() + print hex(w_ad), hex(w_size) + #all_bloc_funcs = del_bloc_in_range([bn.b for bn in known_blocs], w_ad, w_ad+w_size/8) + known_blocs = del_bloc_in_range(known_blocs, w_ad, w_ad+w_size/8) + + code_addr = blocs_to_memory_ranges([bn.b for bn in known_blocs.values()]) + merge_memory_ranges(code_addr) + + reset_code_bloc_pool_py() + for a, b in code_addr: + vm_add_code_bloc(a, b) + + #dump_code_bloc_pool_py() + + vm_reset_exception() + + + return known_blocs, code_addr + +import random + + + +def c_emul_bloc(known_blocs, my_eip): + if not my_eip in known_blocs: + raise ValueError('unknown bloc (should have been disasm...', hex(my_eip)) + return known_blocs[my_eip].module_c.func() + + +class bin_stream_vm(): + def __init__(self, offset = 0L): + self.offset = offset + + def readbs(self, l=1): + s = vm_get_str(self.offset, l) + self.offset+=l + return s + + def writebs(self, l=1): + raise 'writebs unsupported' + + def __str__(self): + raise 'writebs unsupported' + def setoffset(self, val): + val = val & 0xFFFFFFFF + self.offset = val + + + +vm_read_dword = lambda a: struct.unpack('L', vm_get_str(a, 4))[0] +p = lambda addr: struct.pack('L', addr) +pdw = p +updw = lambda bbbb: struct.unpack('L', bbbb)[0] +pw = lambda x: struct.pack('H', x) +upw = lambda x: struct.unpack('H', x)[0] + +#try: +if True: + from emul_lib.libcodenat_interface import * + + #vm_init_regs = libcodenat.vm_init_regs +#except: +# print "WARNING! unable to build libcodenat C interface!!" + + + diff --git a/miasm/tools/win_api.py b/miasm/tools/win_api.py new file mode 100644 index 00000000..378d8cd1 --- /dev/null +++ b/miasm/tools/win_api.py @@ -0,0 +1,1509 @@ +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from to_c_helper import * +import struct +from Crypto.Hash import MD5 +import inspect +from zlib import crc32 +handle_toolhelpsnapshot = 0xaaaa00 +toolhelpsnapshot_info = {} +handle_curprocess = 0xaaaa01 +dbg_present = 0 + +tickcount =0 + +dw_pid_dummy1 = 0x111 +dw_pid_explorer = 0x222 +dw_pid_dummy2 = 0x333 +dw_pid_cur = 0x444 + + +module_fname_nux = None +module_name = "test.exe\x00" +module_path = "c:\\mydir\\"+module_name +module_filesize = None +getversion = 0x0A280105 + +getforegroundwindow = 0x333333 + + +cryptcontext_hwnd = 0x44400 +cryptcontext_bnum = 0x44000 +cryptcontext_num = 0 + +cryptcontext = {} + +phhash_crypt_md5 = 0x55555 + +file_hwnd_num = 0x66600 +files_hwnd = {} +file_offsets = {} + +windowlong_dw = 0x77700 + + +module_cur_hwnd = 0x88800 + +module_file_nul = 0x999000 +runtime_dll = None + +""" +typedef struct tagPROCESSENTRY32 { + DWORD dwSize; + DWORD cntUsage; + DWORD th32ProcessID; + ULONG_PTR th32DefaultHeapID; + DWORD th32ModuleID; + DWORD cntThreads; + DWORD th32ParentProcessID; + LONG pcPriClassBase; + DWORD dwFlags; + TCHAR szExeFile[MAX_PATH]; +} PROCESSENTRY32, *PPROCESSENTRY32; +""" + + +def whoami(): + return inspect.stack()[1][3] + + +class hobj: + pass + + +class mdl: + def __init__(self, ad, l): + self.ad = ad + self.l = l + def __str__(self): + return struct.pack('LL', self.ad, self.l) + +def get_str_ansi(ad_str): + l = 0 + tmp = ad_str + while vm_get_str(tmp, 1) != "\x00": + tmp +=1 + l+=1 + return vm_get_str(ad_str, l) + +def get_str_unic(ad_str): + l = 0 + tmp = ad_str + while vm_get_str(tmp, 2) != "\x00\x00": + tmp +=2 + l+=2 + return vm_get_str(ad_str, l) + + +def kernel32_GlobalAlloc(): + ret_ad = vm_pop_uint32_t() + uflags = vm_pop_uint32_t() + msize = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(uflags), hex(msize), ')' + max_ad = get_memory_page_from_min_ad_py(msize) + + vm_add_memory_page(max_ad, PAGE_READ|PAGE_WRITE, "\x00"*msize) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = max_ad + vm_set_gpreg(regs) + + +def kernel32_GlobalFree(): + ret_ad = vm_pop_uint32_t() + ad = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(ad), ')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + vm_set_gpreg(regs) + +def kernel32_IsDebuggerPresent(): + ret_ad = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', ')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = dbg_present + vm_set_gpreg(regs) + + +def kernel32_CreateToolhelp32Snapshot(): + ret_ad = vm_pop_uint32_t() + dwflags = vm_pop_uint32_t() + th32processid = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(dwflags), hex(th32processid), ')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = handle_toolhelpsnapshot + vm_set_gpreg(regs) + +def kernel32_GetCurrentProcess(): + ret_ad = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', ')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = handle_curprocess + vm_set_gpreg(regs) + +def kernel32_GetCurrentProcessId(): + ret_ad = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', ')' + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = dw_pid_cur + vm_set_gpreg(regs) + + +process_list = [ + [ + 0x40, #DWORD dwSize; + 0, #DWORD cntUsage; + dw_pid_dummy1, #DWORD th32ProcessID; + 0x11111111, #ULONG_PTR th32DefaultHeapID; + 0x11111112, #DWORD th32ModuleID; + 1, #DWORD cntThreads; + dw_pid_explorer, #DWORD th32ParentProcessID; + 0xbeef, #LONG pcPriClassBase; + 0x0, #DWORD dwFlags; + "dummy1.exe" #TCHAR szExeFile[MAX_PATH]; + ], + [ + 0x40, #DWORD dwSize; + 0, #DWORD cntUsage; + dw_pid_explorer, #DWORD th32ProcessID; + 0x11111111, #ULONG_PTR th32DefaultHeapID; + 0x11111112, #DWORD th32ModuleID; + 1, #DWORD cntThreads; + 4, #DWORD th32ParentProcessID; + 0xbeef, #LONG pcPriClassBase; + 0x0, #DWORD dwFlags; + "explorer.exe" #TCHAR szExeFile[MAX_PATH]; + ], + + [ + 0x40, #DWORD dwSize; + 0, #DWORD cntUsage; + dw_pid_dummy2, #DWORD th32ProcessID; + 0x11111111, #ULONG_PTR th32DefaultHeapID; + 0x11111112, #DWORD th32ModuleID; + 1, #DWORD cntThreads; + dw_pid_explorer, #DWORD th32ParentProcessID; + 0xbeef, #LONG pcPriClassBase; + 0x0, #DWORD dwFlags; + "dummy2.exe" #TCHAR szExeFile[MAX_PATH]; + ], + + [ + 0x40, #DWORD dwSize; + 0, #DWORD cntUsage; + dw_pid_cur, #DWORD th32ProcessID; + 0x11111111, #ULONG_PTR th32DefaultHeapID; + 0x11111112, #DWORD th32ModuleID; + 1, #DWORD cntThreads; + dw_pid_explorer, #DWORD th32ParentProcessID; + 0xbeef, #LONG pcPriClassBase; + 0x0, #DWORD dwFlags; + module_name #TCHAR szExeFile[MAX_PATH]; + ], + + +] + +def kernel32_Process32First(): + ret_ad = vm_pop_uint32_t() + s_handle = vm_pop_uint32_t() + ad_pentry = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(s_handle), hex(ad_pentry), ')' + + pentry = struct.pack('LLLLLLLLL', *process_list[0][:-1])+process_list[0][-1] + vm_set_mem(ad_pentry, pentry) + + toolhelpsnapshot_info[s_handle] = 0 + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + + +def kernel32_Process32Next(): + ret_ad = vm_pop_uint32_t() + s_handle = vm_pop_uint32_t() + ad_pentry = vm_pop_uint32_t() + + toolhelpsnapshot_info[s_handle] +=1 + if toolhelpsnapshot_info[s_handle] >= len(process_list): + eax = 0 + else: + eax = 1 + n = toolhelpsnapshot_info[s_handle] + print whoami(), hex(ret_ad), '(', hex(s_handle), hex(ad_pentry), ')' + pentry = struct.pack('LLLLLLLLL', *process_list[n][:-1])+process_list[n][-1] + vm_set_mem(ad_pentry, pentry) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = eax + vm_set_gpreg(regs) + + + + +def kernel32_GetTickCount(): + global tickcount + ret_ad = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', ')' + tickcount +=1 + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = tickcount + vm_set_gpreg(regs) + + +def kernel32_GetVersion(): + ret_ad = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = getversion + vm_set_gpreg(regs) + + +def kernel32_GetPriorityClass(): + ret_ad = vm_pop_uint32_t() + hwnd = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hwnd), ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def kernel32_SetPriorityClass(): + ret_ad = vm_pop_uint32_t() + hwnd = vm_pop_uint32_t() + dwpclass = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hwnd), hex(dwpclass),')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def kernel32_CloseHandle(): + ret_ad = vm_pop_uint32_t() + hwnd = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hwnd),')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + + +def user32_GetForegroundWindow(): + ret_ad = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = getforegroundwindow + vm_set_gpreg(regs) + + + +def user32_FindWindowA(): + ret_ad = vm_pop_uint32_t() + pclassname = vm_pop_uint32_t() + pwindowname = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(pclassname), hex(pwindowname), ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def user32_GetTopWindow(): + ret_ad = vm_pop_uint32_t() + hwnd = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hwnd), ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def user32_BlockInput(): + ret_ad = vm_pop_uint32_t() + b = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(b), ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + + +def advapi32_CryptAcquireContextA(): + ret_ad = vm_pop_uint32_t() + phprov = vm_pop_uint32_t() + pszcontainer = vm_pop_uint32_t() + pszprovider = vm_pop_uint32_t() + dwprovtype = vm_pop_uint32_t() + dwflags = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(phprov), hex(pszcontainer), hex(pszprovider), hex(dwprovtype), hex(dwflags), ')' + + prov = vm_get_str(pszprovider, 0x100) + prov = prov[:prov.find('\x00')] + print 'prov:', prov + + + vm_set_mem(phprov, pdw(cryptcontext_hwnd)) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + + +def advapi32_CryptCreateHash(): + global cryptcontext_num + ret_ad = vm_pop_uint32_t() + hprov = vm_pop_uint32_t() + algid = vm_pop_uint32_t() + hkey = vm_pop_uint32_t() + dwflags = vm_pop_uint32_t() + phhash = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hprov), hex(algid), hex(hkey), hex(dwflags), hex(phhash), ')' + + cryptcontext_num +=1 + + if algid == 0x00008003: + print 'algo is MD5' + vm_set_mem(phhash, pdw(cryptcontext_bnum+cryptcontext_num)) + cryptcontext[cryptcontext_bnum+cryptcontext_num] = hobj() + cryptcontext[cryptcontext_bnum+cryptcontext_num].h = MD5.new() + else: + raise ValueError('un impl algo1') + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + +def advapi32_CryptHashData(): + global cryptcontext + ret_ad = vm_pop_uint32_t() + hhash = vm_pop_uint32_t() + pbdata = vm_pop_uint32_t() + dwdatalen = vm_pop_uint32_t() + dwflags = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hhash), hex(pbdata), hex(dwdatalen), hex(dwflags), ')' + + if not hhash in cryptcontext: + raise ValueError("unknown crypt context") + + data = vm_get_str(pbdata, dwdatalen) + print 'will hash' + print repr(data) + cryptcontext[hhash].h.update(data) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + + +def advapi32_CryptDeriveKey(): + ret_ad = vm_pop_uint32_t() + hprov = vm_pop_uint32_t() + algid = vm_pop_uint32_t() + hbasedata = vm_pop_uint32_t() + dwflags = vm_pop_uint32_t() + phkey = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hprov), hex(algid), hex(hbasedata), hex(dwflags), hex(phkey), ')' + + if algid == 0x6801: + print 'using DES' + else: + raise ValueError('un impl algo2') + + h = cryptcontext[hbasedata].h.digest() + print 'hash', repr(h) + cryptcontext[hbasedata].h_result = h + vm_set_mem(phkey, pdw(hbasedata)) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + +def advapi32_CryptDestroyHash(): + ret_ad = vm_pop_uint32_t() + hhash = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hhash), ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + +def advapi32_CryptDecrypt(): + ret_ad = vm_pop_uint32_t() + hkey = vm_pop_uint32_t() + hhash = vm_pop_uint32_t() + final = vm_pop_uint32_t() + dwflags = vm_pop_uint32_t() + pbdata = vm_pop_uint32_t() + pdwdatalen = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hkey), hex(hhash), hex(final), hex(dwflags), hex(pbdata), hex(pdwdatalen), ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + + fdfsd + +def kernel32_CreateFileA(): + ret_ad = vm_pop_uint32_t() + lpfilename = vm_pop_uint32_t() + dwsharedmode = vm_pop_uint32_t() + lpsecurityattr = vm_pop_uint32_t() + dwcreationdisposition = vm_pop_uint32_t() + dwflagsandattr = vm_pop_uint32_t() + htemplatefile = vm_pop_uint32_t() + + + fname = vm_get_str(lpfilename, 0x100) + fname = fname[:fname.find('\x00')] + + print whoami(), hex(ret_ad), '(', hex(lpfilename), hex(dwsharedmode), hex(lpsecurityattr), hex(dwcreationdisposition), hex(dwflagsandattr), hex(htemplatefile), ')' + my_CreateFile(ret_ad, fname, dwsharedmode, lpsecurityattr, dwcreationdisposition, dwflagsandattr, htemplatefile) + + + + +def kernel32_CreateFileW(): + ret_ad = vm_pop_uint32_t() + lpfilename = vm_pop_uint32_t() + dwsharedmode = vm_pop_uint32_t() + lpsecurityattr = vm_pop_uint32_t() + dwcreationdisposition = vm_pop_uint32_t() + dwflagsandattr = vm_pop_uint32_t() + htemplatefile = vm_pop_uint32_t() + + fname = vm_get_str(lpfilename, 0x100) + fname = fname[:fname.find('\x00\x00')] + fname = fname[::2] + + print whoami(), hex(ret_ad), '(', hex(lpfilename), hex(dwsharedmode), hex(lpsecurityattr), hex(dwcreationdisposition), hex(dwflagsandattr), hex(htemplatefile), ')' + my_CreateFile(ret_ad, fname, dwsharedmode, lpsecurityattr, dwcreationdisposition, dwflagsandattr, htemplatefile) + + +def my_CreateFile(ret_ad, fname, dwsharedmode, lpsecurityattr, dwcreationdisposition, dwflagsandattr, htemplatefile): + print whoami(), hex(ret_ad), '(', fname, hex(dwsharedmode), hex(lpsecurityattr), hex(dwcreationdisposition), hex(dwflagsandattr), hex(htemplatefile), ')' + + print 'fname:', fname + + eax = 0xffffffff + + if fname in [r"\\.\SICE", r"\\.\NTICE", r"\\.\Siwvid"]: + pass + #eax = files_hwnd[fname] = file_hwnd_num + #file_hwnd_num += 1 + elif fname == module_path[:-1]: + eax = module_file_nul + elif fname in ['NUL']: + eax = module_cur_hwnd + else: + raise ValueError('unknown filename') + + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = eax + vm_set_gpreg(regs) + + + +def kernel32_ReadFile(): + ret_ad = vm_pop_uint32_t() + hwnd = vm_pop_uint32_t() + lpbuffer = vm_pop_uint32_t() + nnumberofbytestoread = vm_pop_uint32_t() + lpnumberofbytesread = vm_pop_uint32_t() + lpoverlapped = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hwnd), hex(lpbuffer), hex(nnumberofbytestoread), hex(lpnumberofbytesread), hex(lpoverlapped), ')' + + if hwnd == module_cur_hwnd: + + pass + else: + raise ValueError('unknown hwnd!') + + eax = 0xffffffff + + if hwnd in files_hwnd: + data = files_hwnd[module_cur_hwnd].read(nnumberofbytestoread) + + if (lpnumberofbytesread): + vm_set_mem(lpnumberofbytesread, pdw(len(data))) + vm_set_mem(lpbuffer, data) + + else: + raise ValueError('unknown filename') + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + +def kernel32_GetFileSize(): + ret_ad = vm_pop_uint32_t() + hwnd = vm_pop_uint32_t() + lpfilesizehight = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hwnd), hex(lpfilesizehight), ')' + + if hwnd == module_cur_hwnd: + eax = len(open(module_fname_nux).read()) + else: + raise ValueError('unknown hwnd!') + + if lpfilesizehight != 0: + vm_set_mem(lpfilesizehight, pdw(eax&0xffff0000)) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = eax + vm_set_gpreg(regs) + + +def kernel32_VirtualProtect(): + ret_ad = vm_pop_uint32_t() + lpvoid = vm_pop_uint32_t() + dwsize = vm_pop_uint32_t() + flnewprotect = vm_pop_uint32_t() + lpfloldprotect = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(lpvoid), hex(dwsize), hex(flnewprotect), hex(lpfloldprotect), ')' + + + access_dict = { 0x0: 0, + 0x1: 0, + 0x2: PAGE_READ, + 0x4: PAGE_READ | PAGE_WRITE, + 0x10: PAGE_EXEC, + 0x20: PAGE_EXEC | PAGE_READ, + 0x40: PAGE_EXEC | PAGE_READ | PAGE_WRITE, + 0x100: 0 + } + + access_dict_inv = dict([(x[1], x[0]) for x in access_dict.items()]) + + + if not flnewprotect in access_dict: + raise ValueError( 'unknown access dw!') + + vm_set_mem_access(lpvoid, access_dict[flnewprotect]) + + #XXX todo real old protect + vm_set_mem(lpfloldprotect, pdw(0x40)) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + dump_memory_page_pool_py() + + + +def kernel32_VirtualAlloc(): + ret_ad = vm_pop_uint32_t() + lpvoid = vm_pop_uint32_t() + dwsize = vm_pop_uint32_t() + alloc_type = vm_pop_uint32_t() + flprotect = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(lpvoid), hex(dwsize), hex(alloc_type), hex(flprotect), ')' + + + access_dict = { 0x0: 0, + 0x1: 0, + 0x2: PAGE_READ, + 0x4: PAGE_READ | PAGE_WRITE, + 0x10: PAGE_EXEC, + 0x20: PAGE_EXEC | PAGE_READ, + 0x40: PAGE_EXEC | PAGE_READ | PAGE_WRITE, + 0x100: 0 + } + + access_dict_inv = dict([(x[1], x[0]) for x in access_dict.items()]) + + + if not flprotect in access_dict: + raise ValueError( 'unknown access dw!') + + max_ad = vm_get_memory_page_max_address() + max_ad = (max_ad+0xfff) & 0xfffff000 + + + vm_add_memory_page(max_ad, access_dict[flprotect], "\x00"*dwsize) + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = max_ad + vm_set_gpreg(regs) + dump_memory_page_pool_py() + print 'ret', hex(max_ad), hex(ret_ad) + #XXX for malware tests + #vm_set_mem(regs['esp']-0x2C, pdw(0xFFFFFFFF)) + + +def kernel32_VirtualFree(): + ret_ad = vm_pop_uint32_t() + lpvoid = vm_pop_uint32_t() + dwsize = vm_pop_uint32_t() + alloc_type = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(lpvoid), hex(dwsize), hex(alloc_type), ')' + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + vm_set_gpreg(regs) + + +def user32_GetWindowLongA(): + ret_ad = vm_pop_uint32_t() + hwnd = vm_pop_uint32_t() + nindex = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hwnd), hex(nindex), ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = windowlong_dw + vm_set_gpreg(regs) + + +def user32_SetWindowLongA(): + ret_ad = vm_pop_uint32_t() + hwnd = vm_pop_uint32_t() + nindex = vm_pop_uint32_t() + newlong = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hwnd), hex(nindex), hex(newlong), ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = windowlong_dw + vm_set_gpreg(regs) + + + +def kernel32_GetModuleFileNameA(): + ret_ad = vm_pop_uint32_t() + hmodule = vm_pop_uint32_t() + lpfilename = vm_pop_uint32_t() + nsize = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), '(', hex(hmodule), hex(lpfilename), hex(nsize), ')' + + if hmodule in [0]: + p = module_path[:] + else: + raise ValueError('unknown module h') + + + if nsize < len(p): + eax = nsize + p = p[:nsize] + else: + eax = len(p) + print repr(p) + vm_set_mem(lpfilename, p) + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = nsize + vm_set_gpreg(regs) + +lastwin32error = 0 +def kernel32_GetLastError(): + ret_ad = vm_pop_uint32_t() + global lastwin32error + + print whoami(), hex(ret_ad), '(', ')' + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = lastwin32error + vm_set_gpreg(regs) + + +def kernel32_LoadLibraryA(): + ret_ad = vm_pop_uint32_t() + dllname = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), hex(dllname) + + libname = vm_get_str(dllname, 0x100) + libname = libname[:libname.find('\x00')] + print repr(libname) + + eax = runtime_dll.lib_get_add_base(libname) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = eax + vm_set_gpreg(regs) + +def kernel32_GetProcAddress(): + ret_ad = vm_pop_uint32_t() + libbase = vm_pop_uint32_t() + fname = vm_pop_uint32_t() + print whoami(), hex(ret_ad), hex(fname), hex(libbase) + fname = fname & 0xFFFFFFFF + if fname < 0x10000: + fname = fname + else: + fname = vm_get_str(fname, 0x100) + fname = fname[:fname.find('\x00')] + print repr(fname) + + + ad = runtime_dll.lib_get_add_func(libbase, fname) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = ad + vm_set_gpreg(regs) + + + +def kernel32_LoadLibraryW(): + ret_ad = vm_pop_uint32_t() + dllname = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), hex(dllname) + + libname = vm_get_str(dllname, 0x100) + libname = libname[:libname.find('\x00\x00')] + libname = libname[::2] + print repr(libname) + + eax = runtime_dll.lib_get_add_base(libname) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = eax + vm_set_gpreg(regs) + + +def kernel32_GetModuleHandleA(): + ret_ad = vm_pop_uint32_t() + dllname = vm_pop_uint32_t() + print whoami(), hex(ret_ad), hex(dllname) + + if dllname: + libname = vm_get_str(dllname, 0x100) + libname = libname[:libname.find('\x00')] + print libname + eax = runtime_dll.lib_get_add_base(libname) + else: + eax = e.Opthdr.Opthdr.ImageBase + print "default img base" , hex(eax) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = eax + vm_set_gpreg(regs) + + +def kernel32_GetSystemInfo(): + ret_ad = vm_pop_uint32_t() + sys_ptr = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), hex(sys_ptr) + + vm_set_mem(sys_ptr, "\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x01\x00\xFF\xFF\xFE\x7F\x0F\x00\x00\x00\x04\x00\x00\x00\x4A\x02\x00\x00\x00\x00\x01\x00\x06\x00\x0B\x0F") + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + #regs['eax'] = 0 + vm_set_gpreg(regs) + + +def kernel32_IsWow64Process(): + ret_ad = vm_pop_uint32_t() + h = vm_pop_uint32_t() + bool_ptr = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), hex(h), hex(bool_ptr) + + vm_set_mem(bool_ptr, pdw(0)) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + +def kernel32_GetCommandLineA(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 1 + vm_set_gpreg(regs) + +cryptdll_md5_h = {} +def cryptdll_MD5Init(): + global cryptdll_MD5Init + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + ad_ctx = vm_pop_uint32_t() + index = len(cryptdll_md5_h) + h = MD5.new() + cryptdll_md5_h[index] = h + + vm_set_mem(ad_ctx, pdw(index)) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + vm_set_gpreg(regs) + + + +def cryptdll_MD5Update(): + global cryptdll_MD5Init + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + ad_ctx = vm_pop_uint32_t() + ad_input = vm_pop_uint32_t() + inlen = vm_pop_uint32_t() + + index = vm_get_str(ad_ctx, 4) + index = updw(index) + if not index in cryptdll_md5_h: + raise ValueError('unknown h context', index) + + data = vm_get_str(ad_input, inlen) + cryptdll_md5_h[index].update(data) + print hexdump(data) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + vm_set_gpreg(regs) + +def cryptdll_MD5Final(): + global cryptdll_MD5Init + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + + ad_ctx = vm_pop_uint32_t() + + index = vm_get_str(ad_ctx, 4) + index = updw(index) + if not index in cryptdll_md5_h: + raise ValueError('unknown h context', index) + + h = cryptdll_md5_h[index].digest() + vm_set_mem(ad_ctx + 88, h) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + vm_set_gpreg(regs) + +def ntdll_RtlInitAnsiString(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + ad_ctx = vm_pop_uint32_t() + ad_str = vm_pop_uint32_t() + + s = get_str_ansi(ad_str) + l = len(s) + print "string", l, s + vm_set_mem(ad_ctx, pw(l)+pw(l+1)+pdw(ad_str)) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + vm_set_gpreg(regs) + + +def ntdll_RtlAnsiStringToUnicodeString(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + ad_ctxu = vm_pop_uint32_t() + ad_ctxa = vm_pop_uint32_t() + alloc_dst = vm_pop_uint32_t() + + + l1, l2, ptra = struct.unpack('HHL', vm_get_str(ad_ctxa, 8)) + print hex(l1), hex(l2), hex(ptra) + + s = vm_get_str(ptra, l1) + print s + s = '\x00'.join(s) + "\x00\x00" + if alloc_dst: + ad = get_memory_page_max_address_py() + ad = (ad + 0xFFF) & ~0xFFF + vm_add_memory_page(ad , PAGE_READ | PAGE_WRITE, s) + + vm_set_mem(ad_ctxu, pw(len(s))+pw(len(s)+1)+pdw(ad)) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def ntdll_RtlHashUnicodeString(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + ad_ctxu = vm_pop_uint32_t() + case_i = vm_pop_uint32_t() + h_id = vm_pop_uint32_t() + phout = vm_pop_uint32_t() + + print hex(h_id) + if h_id != 1: + raise ValueError('unk hash unicode', h_id) + + l1, l2, ptra = struct.unpack('HHL', vm_get_str(ad_ctxu, 8)) + print hex(l1), hex(l2), hex(ptra) + s = vm_get_str(ptra, l1) + print repr(s) + s = s[::2][:-1] + print repr(s) + hv = 0 + + if case_i: + s = s.lower() + for c in s: + hv = ((65599*hv)+ord(c) )&0xffffffff + print "unicode h", hex(hv) + + vm_set_mem(phout, pdw(hv)) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def ntdll_RtlFreeUnicodeString(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + ad_ctxu = vm_pop_uint32_t() + + l1, l2, ptra = struct.unpack('HHL', vm_get_str(ad_ctxu, 8)) + print l1, l2, hex(ptra) + s = vm_get_str(ptra, l1) + print 'free', repr(s) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + vm_set_gpreg(regs) + + + +def kernel32_RtlMoveMemory(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + ad_dst = vm_pop_uint32_t() + ad_src = vm_pop_uint32_t() + m_len = vm_pop_uint32_t() + + print hex(ad_dst), hex(ad_src), hex(m_len) + data = vm_get_str(ad_src, m_len) + vm_set_mem(ad_dst, data) + print hexdump(data) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + vm_set_gpreg(regs) + + +def ntdll_RtlAnsiCharToUnicodeChar(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + ad_ad_ch = vm_pop_uint32_t() + + print hex(ad_ad_ch) + ad_ch = updw(vm_get_str(ad_ad_ch, 4)) + print hex(ad_ch) + + ch = ord(vm_get_str(ad_ch, 1)) + vm_set_mem(ad_ad_ch, pdw(ad_ch+1)) + + print repr(ch), repr(chr(ch)) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = ch + vm_set_gpreg(regs) + +def ntdll_RtlFindCharInUnicodeString(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + flags = vm_pop_uint32_t() + main_str_ad = vm_pop_uint32_t() + search_chars_ad = vm_pop_uint32_t() + pos_ad = vm_pop_uint32_t() + + print flags + if flags != 0: + raise ValueError('unk flags') + + ml1, ml2, mptra = struct.unpack('HHL', vm_get_str(main_str_ad, 8)) + print ml1, ml2, hex(mptra) + sl1, sl2, sptra = struct.unpack('HHL', vm_get_str(search_chars_ad, 8)) + print sl1, sl2, hex(sptra) + + main_data= vm_get_str(mptra, ml1)[:-1] + search_data= vm_get_str(sptra, sl1)[:-1] + + print repr(main_data[::2]) + print repr(search_data) + + pos = None + for i, c in enumerate(main_data): + for s in search_data: + if s == c: + pos = i + break + if pos: + break + + print pos + regs = vm_get_gpreg() + regs['eip'] = ret_ad + if pos == None: + regs['eax'] = 0xC0000225 + vm_set_mem(pos_ad, pdw(0)) + else: + regs['eax'] = 0 + vm_set_mem(pos_ad, pdw(pos)) + + vm_set_gpreg(regs) + print 'ret', hex(regs['eax']) + +def ntdll_RtlComputeCrc32(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + dwinit = vm_pop_uint32_t() + pdata = vm_pop_uint32_t() + ilen = vm_pop_uint32_t() + + + data = vm_get_str(pdata, ilen) + print hex(dwinit) + print hexdump(data) + crc_r = crc32(data, dwinit) + print "crc32", hex(crc_r) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = crc_r + vm_set_gpreg(regs) + + + +def ntdll_RtlExtendedIntegerMultiply(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + b2 = vm_pop_uint32_t() + b1 = vm_pop_uint32_t() + bm = vm_pop_uint32_t() + + print hex(b1), hex(b2), hex(bm) + a = (b1<<32)+b2 + a = a*bm + print hex(a) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = (a&0xffffffff) + regs['edx'] = (a>>32)&0xffffffff + + vm_set_gpreg(regs) + +def ntdll_RtlLargeIntegerAdd(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + a2 = vm_pop_uint32_t() + a1 = vm_pop_uint32_t() + b2 = vm_pop_uint32_t() + b1 = vm_pop_uint32_t() + + print hex(a1), hex(a2), hex(b1), hex(b2) + a = (a1<<32)+a2 + (b1<<32)+b2 + print hex(a) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = (a&0xffffffff) + regs['edx'] = (a>>32)&0xffffffff + + vm_set_gpreg(regs) + +def ntdll_RtlLargeIntegerShiftRight(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + a2 = vm_pop_uint32_t() + a1 = vm_pop_uint32_t() + m = vm_pop_uint32_t() + + print hex(a1), hex(a2), hex(m) + a = ((a1<<32)+a2)>>m + print hex(a) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = (a&0xffffffff) + regs['edx'] = (a>>32)&0xffffffff + + vm_set_gpreg(regs) + +def ntdll_RtlEnlargedUnsignedMultiply(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + a = vm_pop_uint32_t()&0xFFFFFFFF + b = vm_pop_uint32_t()&0xFFFFFFFF + + print hex(a), hex(b) + a = a*b + print hex(a) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = (a&0xffffffff) + regs['edx'] = (a>>32)&0xffffffff + + vm_set_gpreg(regs) + +def ntdll_RtlLargeIntegerSubtract(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + a2 = vm_pop_uint32_t() + a1 = vm_pop_uint32_t() + b2 = vm_pop_uint32_t() + b1 = vm_pop_uint32_t() + + print hex(a1), hex(a2), hex(b1), hex(b2) + a = (a1<<32)+a2 - (b1<<32)+b2 + print hex(a) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = (a&0xffffffff) + regs['edx'] = (a>>32)&0xffffffff + + vm_set_gpreg(regs) + + +def ntdll_RtlCompareMemory(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + ad1 = vm_pop_uint32_t() + ad2 = vm_pop_uint32_t() + m_len = vm_pop_uint32_t() + + print hex(ad1), hex(ad2), hex(m_len) + data1 = vm_get_str(ad1, m_len) + data2 = vm_get_str(ad2, m_len) + + print hexdump(data1) + print hexdump(data2) + i = 0 + while data1[i] == data2[i]: + i+=1 + if i >=m_len: + break + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = i + vm_set_gpreg(regs) + print 'compare ret:', i + + +def user32_GetMessagePos(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0x00110022 + vm_set_gpreg(regs) + +def kernel32_Sleep(): + ret_ad = vm_pop_uint32_t() + t = vm_pop_uint32_t() + print whoami(), hex(ret_ad), hex(t) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + vm_set_gpreg(regs) + + #XXX for malware tests + vm_set_mem(regs['esp']-0x20, pdw(0xFFFFFFFF)) + +def ntdll_ZwUnmapViewOfSection(): + ret_ad = vm_pop_uint32_t() + h = vm_pop_uint32_t() + ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad), hex(h), hex(ad) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def kernel32_IsBadReadPtr(): + ret_ad = vm_pop_uint32_t() + lp = vm_pop_uint32_t() + ucb = vm_pop_uint32_t() + print whoami(), hex(ret_ad), hex(lp), hex(ucb) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +win_event_num = 0x13370 +def ntoskrnl_KeInitializeEvent(): + global win_event_num + ret_ad = vm_pop_uint32_t() + my_event = vm_pop_uint32_t() + my_type = vm_pop_uint32_t() + my_state = vm_pop_uint32_t() + print whoami(), hex(ret_ad), hex(my_event), hex(my_type), hex(my_state) + vm_set_mem(my_event, pdw(win_event_num)) + win_event_num +=1 + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + + + + +def ntoskrnl_RtlGetVersion(): + ret_ad = vm_pop_uint32_t() + ptr_version = vm_pop_uint32_t() + print whoami(), hex(ret_ad), hex(ptr_version) + + s = struct.pack('LLLLL', 0x88000000,0x88000001,0x88000002,0x88000003,0x88000004 ) + vm_set_mem(ptr_version, s) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def hal_ExAcquireFastMutex(): + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +nt_mdl = {} +nt_mdl_ad = None +nt_mdl_cur = 0 + +def mdl2ad(n): + return nt_mdl_ad+0x10*n + +def ad2mdl(ad): + return ((ad-nt_mdl_ad)&0xFFFFFFFFL)/0x10 + +def ntoskrnl_IoAllocateMdl(): + global nt_mdl, nt_mdl_ad, nt_mdl_cur + ret_ad = vm_pop_uint32_t() + v_addr = vm_pop_uint32_t() + l = vm_pop_uint32_t() + second_buf = vm_pop_uint32_t() + chargequota = vm_pop_uint32_t() + pirp = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), hex(v_addr), hex(l), hex(second_buf), hex(chargequota), hex(pirp) + m = mdl(v_addr, l) + nt_mdl[nt_mdl_cur] = m + vm_set_mem(mdl2ad(nt_mdl_cur), str(m)) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = mdl2ad(nt_mdl_cur) + vm_set_gpreg(regs) + + nt_mdl_cur += 1 + +def ntoskrnl_MmProbeAndLockPages(): + global nt_mdl, nt_mdl_ad, nt_mdl_cur + ret_ad = vm_pop_uint32_t() + p_mdl = vm_pop_uint32_t()&0xffffffff + access_mode = vm_pop_uint32_t() + op = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), hex(p_mdl), hex(access_mode), hex(op) + + if not ad2mdl(p_mdl) in nt_mdl: + raise ValueError('unk mdl', hex(p_mdl)) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def ntoskrnl_MmMapLockedPagesSpecifyCache(): + global nt_mdl, nt_mdl_ad, nt_mdl_cur + ret_ad = vm_pop_uint32_t() + p_mdl = vm_pop_uint32_t()&0xffffffff + access_mode = vm_pop_uint32_t() + cache_type = vm_pop_uint32_t() + base_ad = vm_pop_uint32_t() + bugcheckonfailure = vm_pop_uint32_t() + priority = vm_pop_uint32_t() + + print whoami(), hex(ret_ad), hex(p_mdl), hex(access_mode), hex(cache_type), hex(base_ad), hex(bugcheckonfailure), hex(priority) + if not ad2mdl(p_mdl) in nt_mdl: + raise ValueError('unk mdl', hex(p_mdl)) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = nt_mdl[ad2mdl(p_mdl)].ad + vm_set_gpreg(regs) + +def ntoskrnl_MmProtectMdlSystemAddress(): + global nt_mdl, nt_mdl_ad, nt_mdl_cur + ret_ad = vm_pop_uint32_t() + p_mdl = vm_pop_uint32_t()&0xffffffff + prot = vm_pop_uint32_t() + print whoami(), hex(ret_ad), hex(p_mdl), hex(prot) + if not ad2mdl(p_mdl) in nt_mdl: + raise ValueError('unk mdl', hex(p_mdl)) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def ntoskrnl_MmUnlockPages(): + global nt_mdl, nt_mdl_ad, nt_mdl_cur + ret_ad = vm_pop_uint32_t() + p_mdl = vm_pop_uint32_t()&0xffffffff + print whoami(), hex(ret_ad), hex(p_mdl) + if not ad2mdl(p_mdl) in nt_mdl: + raise ValueError('unk mdl', hex(p_mdl)) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def ntoskrnl_IoFreeMdl(): + global nt_mdl, nt_mdl_ad, nt_mdl_cur + ret_ad = vm_pop_uint32_t() + p_mdl = vm_pop_uint32_t()&0xffffffff + print whoami(), hex(ret_ad), hex(p_mdl) + if not ad2mdl(p_mdl) in nt_mdl: + raise ValueError('unk mdl', hex(p_mdl)) + del(nt_mdl[ad2mdl(p_mdl)]) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def hal_ExReleaseFastMutex(): + global nt_mdl, nt_mdl_ad, nt_mdl_cur + ret_ad = vm_pop_uint32_t() + print whoami(), hex(ret_ad) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + +def ntoskrnl_RtlQueryRegistryValues(): + global nt_mdl, nt_mdl_ad, nt_mdl_cur + ret_ad = vm_pop_uint32_t() + relativeto = vm_pop_uint32_t() + path = vm_pop_uint32_t() + querytable = vm_pop_uint32_t() + context = vm_pop_uint32_t() + environ = vm_pop_uint32_t() + print whoami(), hex(ret_ad), hex(relativeto), hex(path), hex(querytable), hex(context), hex(environ) + p = get_str_unic(path) + print repr(p[::2]) + + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = 0 + vm_set_gpreg(regs) + + +def ntoskrnl_ExAllocatePoolWithTagPriority(): + global nt_mdl, nt_mdl_ad, nt_mdl_cur + ret_ad = vm_pop_uint32_t() + pool_type = vm_pop_uint32_t() + nbr_of_bytes = vm_pop_uint32_t() + tag = vm_pop_uint32_t() + priority = vm_pop_uint32_t() + print whoami(), hex(ret_ad), hex(pool_type), hex(nbr_of_bytes), hex(tag), hex(priority) + + max_ad = vm_get_memory_page_max_address() + max_ad = (max_ad+0xfff) & 0xfffff000 + + + vm_add_memory_page(max_ad, PAGE_READ|PAGE_WRITE, "\x00"*nbr_of_bytes) + regs = vm_get_gpreg() + regs['eip'] = ret_ad + regs['eax'] = max_ad + vm_set_gpreg(regs) + + print "ad", hex(max_ad) diff --git a/setup.py b/setup.py new file mode 100755 index 00000000..f3a2be16 --- /dev/null +++ b/setup.py @@ -0,0 +1,29 @@ +#! /usr/bin/env python + +from distutils.core import setup,Extension + +setup( + name = 'Miasm', + version = '0.1', + packages=['miasm', 'miasm/tools', + 'miasm/expression', 'miasm/graph', 'miasm/arch', + 'miasm/core', 'miasm/tools/emul_lib' ], + package_data = {'miasm':['tools/emul_lib/*.h']}, +# data_files = [('toto', ['miasm/tools/emul_lib/queue.h'])], + ext_modules = [ + Extension("miasm.tools.emul_lib.libcodenat_interface", + ["miasm/tools/emul_lib/libcodenat_interface.c", + "miasm/tools/emul_lib/libcodenat.c"]), + Extension("miasm.tools.emul_lib.libcodenat_tcc", + ["miasm/tools/emul_lib/libcodenat_tcc.c"], + libraries=["tcc"]) + ], + + # Metadata + author = 'Fabrice Desclaux', + author_email = 'serpilliere@droid-corp.org', + description = 'Machine code manipulation library', + license = 'GPLv2', + # keywords = '', + # url = '', +) |