From bbb96f6381bd140bf926ac43f83de7ba3c4be6d7 Mon Sep 17 00:00:00 2001 From: Horde Nicolas Date: Tue, 13 Jul 2021 09:30:52 +0200 Subject: [PATCH] =?UTF-8?q?Pas=20=C3=A0=20pas=20&=20pas=20=C3=A0=20pas=20d?= =?UTF-8?q?=C3=A9taill=C3=A9=20fonctionnel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ia86.cpp | 229 ++++++++++++++++++++++++++++++++++--------------- ia86.h | 41 +++++---- scenarios.json | 39 +++++++-- 3 files changed, 212 insertions(+), 97 deletions(-) diff --git a/ia86.cpp b/ia86.cpp index a6259f7..0e6334d 100644 --- a/ia86.cpp +++ b/ia86.cpp @@ -80,6 +80,17 @@ Scenario scenario; Unasm unasm; int marker; bool debug=true; +uc_hook uh_mem; +uc_hook uh_code; +uc_hook uh_call; +uc_hook uh_int; +bool step=false; +bool call=false; +bool ok=false; +bool executed=false; +bool initialized=false; +uint32_t hadcall=0x0; + //---------------------------------------------------------------------- // Classe ScenarioWindow //---------------------------------------------------------------------- @@ -153,7 +164,6 @@ InstructionWindow::InstructionWindow (finalcut::FWidget* parent) { listview.ignorePadding(); - listview.addColumn ("P"); listview.addColumn ("Adresse"); listview.addColumn ("Opcodes "); listview.addColumn ("Mnémo."); @@ -162,7 +172,7 @@ InstructionWindow::InstructionWindow (finalcut::FWidget* parent) listview.setFocus(); } -std::vector> InstructionWindow::get() +std::vector> InstructionWindow::get() { return content; } @@ -183,7 +193,7 @@ int InstructionWindow::getsize() return listview.getCount(); } -void InstructionWindow::set(std::vector> src) +void InstructionWindow::set(std::vector> src) { content=src; listview.clear(); @@ -284,7 +294,7 @@ void TextWindow::append(const finalcut::FString& str) std::string TextWindow::get() { - return scrolltext.getText().toString () ; + return scrolltext.getText().toString() ; } void TextWindow::set(const finalcut::FString& str) @@ -316,18 +326,18 @@ void TextWindow::adjustSize() // Classe Desassembler //---------------------------------------------------------------------- -Desassembler::Desassembler(TextWindow *log) : log(log) +Desassembler::Desassembler(Menu *widget) : widget(widget) { try { err = cs_open(CS_ARCH_X86, CS_MODE_16, &handle); if (err != CS_ERR_OK) throw Error("Désassembleur - initialisation....................[ERREUR]"); - log->append("Désassembleur - initialisation....................[ OK ]"); + widget->log.append("Désassembleur - initialisation....................[ OK ]"); } catch(exception const& e) { - log->append(e.what()); + widget->log.append(e.what()); } } @@ -341,7 +351,7 @@ void Desassembler::Desassemble(uint8_t *content, uint32_t address,uint32_t size, throw Error("Désassembleur - désassemblage.....................[ERREUR]"); else { - if (debug) log->append("Désassemblage - désassemblage.....................[ "+to_string(srcsize)+"l ]"); + if (debug) widget->log.append("Désassemblage - désassemblage.....................[ "+to_string(srcsize)+"l ]"); unasm->src.clear(); unasm->pos.clear(); for (size_t j = 0; j < srcsize; j++) @@ -352,7 +362,7 @@ void Desassembler::Desassemble(uint8_t *content, uint32_t address,uint32_t size, std::string adresse = intToHexString((int)insn[j].address, 8); std::string *menmonic = new std::string((char *)insn[j].mnemonic); std::string *op_str = new std::string((char *)insn[j].op_str); - std::array *array = new std::array{"", adresse, *bytes, *menmonic, *op_str}; + std::array *array = new std::array{adresse, *bytes, *menmonic, *op_str}; unasm->src.push_back(*array); unasm->pos.push_back(insn[j].address); } @@ -363,7 +373,7 @@ void Desassembler::Desassemble(uint8_t *content, uint32_t address,uint32_t size, { unasm->src.clear(); unasm->pos.clear(); - log->append(e.what()); + widget->log.append(e.what()); } } @@ -372,18 +382,18 @@ void Desassembler::Desassemble(uint8_t *content, uint32_t address,uint32_t size, // Classe Assembler //---------------------------------------------------------------------- -Assembler::Assembler(TextWindow *log) : log(log) +Assembler::Assembler(Menu *widget) : widget(widget) { try { err = ks_open(KS_ARCH_X86, KS_MODE_16, &ks); if (err != KS_ERR_OK) throw Error("Assembleur - initialisation.......................[ERREUR]"); - log->append("Assembleur - initialisation.......................[ OK ]"); + widget->log.append("Assembleur - initialisation.......................[ OK ]"); } catch(exception const& e) { - log->append(e.what()); + widget->log.append(e.what()); } ks_option(ks, KS_OPT_SYNTAX, KS_OPT_SYNTAX_NASM); } @@ -426,13 +436,13 @@ std::vector Assembler::MultiAssemble(std::string source,uint32_t address) mcode.push_back(*code); for(size_t i=0;iAssemble(&mcode[i]); - log->append("Assembleur - assemblage...........................[ OK ]"); + widget->log.append("Assembleur - assemblage...........................[ OK ]"); return mcode; } catch(exception const& e) { std::vector mcode; - log->append(e.what()); + widget->log.append(e.what()); return mcode; } @@ -449,7 +459,7 @@ void Assembler::Assemble(Code *code) code->size=0; code->assembled=false; code->loaded=false; - throw Error("Assembleur - assemblage...........................[ERREUR]"); + throw Error("Assembleur - assemblage...........................[ERREUR]\n Nombre:"+to_string(srcsize)+"\n Erreur:"+std::string(ks_strerror(ks_errno(ks)))); } else code->assembled=true; @@ -459,7 +469,7 @@ void Assembler::Assemble(Code *code) // Classe VMEngine //---------------------------------------------------------------------- -VMEngine::VMEngine(TextWindow *log) : log(log) +VMEngine::VMEngine(Menu *widget) : widget(widget) { code=new uint8_t[500]; Init(); @@ -623,25 +633,26 @@ void VMEngine::Init() { try { + hadcall=0; err = uc_open(UC_ARCH_X86, UC_MODE_16, &uc); if (err != UC_ERR_OK) throw Error("VM IA86 - initilisation...........................[ERREUR]"); - log->append("VM IA86 - initilisation...........................[ OK ]"); + widget->log.append("VM IA86 - initilisation...........................[ OK ]"); } catch(exception const& e) { - log->append(e.what()); + widget->log.append(e.what()); } } bool VMEngine::isExecuted() { - return this->executed; + return executed; } bool VMEngine::isInitialized() { - return this->initialized; + return initialized; } void VMEngine::Close() @@ -651,31 +662,17 @@ void VMEngine::Close() void VMEngine::Halt() { - if (this->executed) - log->append("VM IA86 - arret...................................[ INFO ]"); - this->executed=false; + if (executed) + widget->log.append("VM IA86 - arret...................................[ INFO ]"); + executed=false; } void VMEngine::Unconfigure() { this->Halt(); - if (this->initialized) - log->append("VM IA86 - déconfiguration.........................[ INFO ]"); - this->initialized=false; -} - -uint32_t VMEngine::getNextInstr() -{ - uint32_t now=getEIP(); - bool flag=false; - for(int pos: unasm.pos) - { - if (pos==now) - flag=true; - else if (flag) - return pos; - } - return 0; + if (initialized) + widget->log.append("VM IA86 - déconfiguration.........................[ INFO ]"); + initialized=false; } std::string VMEngine::getRam(int segment, int address,int lines, int linesize) @@ -708,7 +705,7 @@ std::string VMEngine::getRam(int segment, int address,int lines, int linesize) return result; } -std::vector> VMEngine::getInstr(int segment, int address,int size) +std::vector> VMEngine::getInstr(int segment, int address,int size) { uint32_t realaddress=segment*16+address; if (realaddressbufferaddress+500) @@ -743,10 +740,10 @@ std::vector> VMEngine::getInstr(int segment, int addr int last=first+size; marker=0; std::string reference=intToHexString(address, 8); - std::vector> result = {unasm.src.begin()+first,unasm.src.begin()+last}; - for(std::array item: result) + std::vector> result = {unasm.src.begin()+first,unasm.src.begin()+last}; + for(std::array item: result) { - if (item[1]==reference) + if (item[0]==reference) break; marker++; } @@ -758,7 +755,64 @@ int VMEngine::getLine() { return marker; } + +//---------------------------------------------------------------------- +// Hook +//---------------------------------------------------------------------- + +static void hook_int(uc_engine *uc, uint32_t intno, void *user_data) +{ + ((Menu *)user_data)->tolog("INT "+to_string(intno)); +} + +static void hook_code (uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + if (!ok) + { + ok=true; + return; + } + uint8_t code[2]; + uc_err err = uc_mem_read(uc, address, &code, 2); + if (err) + throw Error("VM IA86 - hook instructions.......................[ERREUR]"); + //((Menu *)user_data)->tolog(intToHexString(code[0],2)); + //((Menu *)user_data)->tolog(intToHexString(code[1],2)); + if (code[0]==0xF4) + executed=false; + else if (step && (code[0]==0xE8 || code[0]==0xFF || code[0]==0x9A || (code[0]==0x66 && (code[1]==0xE8 || code[1]==0xFF || code[1]==0x9A)))) + hadcall=address+size; + else if (!step || (hadcall>0 && !call)) return; + uc_emu_stop(uc); +} + +static void hook_call(uc_engine *uc, uint32_t intno, void *user_data) +{ + ((Menu *)user_data)->tolog("SYSCALL"); +} + + +static void hook_memory_write(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) +{ + switch (type) + { + case UC_MEM_WRITE: + if ((address>=0xB8000) && (address<=0xB8000+80*25*2)) + { + uint16_t offset=address-0xB8000; + uint16_t y=(int)(offset/(80*2)); + uint16_t x=offset%(80*2); + char achar; + if (std::isprint(value)) + achar=(char)value; + else + achar='.'; + if ((size==1) && (x%2==0)) + ((Menu *)user_data)->SetScreen(x/2,y,achar); + } + } +} void VMEngine::Configure(State *init, std::string code) { try @@ -771,31 +825,35 @@ void VMEngine::Configure(State *init, std::string code) Close(); Init(); bufferaddress=-666; - this->initialized=false; - this->executed=false; - //log->append("Mappage de la mémoire virtuelle"); + initialized=false; + executed=false; + //widget->log.append("Mappage de la mémoire virtuelle"); uc_mem_map(uc, 0, 1 * 1024 * 1024, UC_PROT_ALL); + uc_hook_add(uc, &uh_call, UC_HOOK_INSN, (void*)hook_call, (void*)widget, 1, 0, UC_X86_INS_SYSCALL); + uc_hook_add(uc, &uh_mem, UC_HOOK_MEM_WRITE, (void*)hook_memory_write, (void*)widget, 1, 0); + uc_hook_add(uc, &uh_code, UC_HOOK_CODE, (void*)hook_code, (void*)widget, 1, 0); + uc_hook_add(uc, &uh_int, UC_HOOK_INTR, (void*)hook_int, (void*)widget, 1, 0); for(size_t i=0;iappend("Section N°"+std::to_string(i)+" : "+intToHexString(mcode[i].address,8)+" -> "+to_string(mcode[i].size)+" octets"); + if (debug) widget->log.append("Section N°"+std::to_string(i)+" : "+intToHexString(mcode[i].address,8)+" -> "+to_string(mcode[i].size)+" octets"); } status=verify(); if (status==0) { - this->initialized=true; + initialized=true; SetRegs(init); } else - this->initialized=false; + initialized=false; } catch(exception const& e) { - log->append(e.what()); - this->initialized=false; + widget->log.append(e.what()); + initialized=false; } } @@ -964,37 +1022,42 @@ void VMEngine::SetRegs(State *init) out << " AX=" << std::uppercase << std::setfill('0') << std::setw(4) << std::hex << init->dump.regs.ax << " "; else out << "EAX=" << std::uppercase << std::setfill('0') << std::setw(8) << std::hex << init->dump.regs.eax << " "; - log->append(out.str()); + widget->log.append(out.str()); } -void VMEngine::Run(uint32_t end,uint64_t timeout) +void VMEngine::Run(bool astep, bool acall, uint64_t timeout) { try { - if (verify()==0 && this->initialized) + if (verify()==0 && initialized) { - err=uc_emu_start(uc, this->getCurrent(), end, timeout, 0); + ok=false; + step=astep; + call=acall; + if (hadcall==0) + err=uc_emu_start(uc, this->getCurrent(), 0xFFFFFFFF, timeout, 0); + else + { + err=uc_emu_start(uc, this->getCurrent(), hadcall, timeout, 0); + hadcall=0; + } if (err) throw Error("VM IA86 - execution...............................[ERREUR]"); else { - if (!this->executed) - log->append("VM IA86 - execution...............................[ INFO ]"); - this->executed="true"; + if (!executed) + widget->log.append("VM IA86 - execution...............................[ INFO ]"); + executed="true"; } } } catch(exception const& e) { this->Halt(); - log->append(e.what()); + widget->log.append(e.what()); } } -//---------------------------------------------------------------------- -// Classe -//---------------------------------------------------------------------- - //---------------------------------------------------------------------- // Classe Menu //---------------------------------------------------------------------- @@ -1090,7 +1153,7 @@ void Menu::initWindows() } // Level 1 : IP AL -// Level 2 : IP AX +// Level 2 : I:P AX // Level 3 : IP AX BX CX DX // Level 4 : IP AX BX CX DX FLAGS // Level 5 : IP AX BX CX DX FLAGS SI DI @@ -1112,7 +1175,7 @@ void Menu::AdjustWindows() stack.setGeometry ( FPoint { 43, 01 }, FSize{15, 15} ); mem.setGeometry ( FPoint { 77, 01 }, FSize{108, 15} ); tuto.setGeometry ( FPoint { 125, 45 }, FSize{60, 11} ); - screen.setGeometry ( FPoint { 105, 18 }, FSize{80, 25} ); + screen.setGeometry ( FPoint { 103, 16 }, FSize{82, 28} ); debug.setGeometry ( FPoint { 42, 17 }, FSize{60, 27} ); scenar.setGeometry ( FPoint { 187, 01 }, FSize{25, 55} ); this->hide(); @@ -1167,6 +1230,26 @@ void Menu::initMenus() About.setStatusbarMessage ("A propos de IA86"); } +void Menu::ClearScreen() +{ + std::string empty=""; + for(int i=0;i<80*25;i++) + { + if ((i%80==0) && i!=0) + empty+="\n"; + empty+="X"; + } + screen.set(empty); +} + +void Menu::SetScreen(uint16_t x, uint16_t y, char value) +{ + std::string temp=screen.get(); + if (x<25 && y<80) + temp[x+y*81]=value; + screen.set(temp); +} + void Menu::onTimer (finalcut::FTimerEvent* ev) { refresh(); @@ -1284,9 +1367,15 @@ void Menu::end() void Menu::compile() { vm.Configure(&scenario.levels[scenar.getselected()].init,edit.get()); + ClearScreen(); showInstr(); } +void Menu::tolog(std::string str) +{ + log.append(str); +} + void Menu::about() { log.hide(); @@ -1366,7 +1455,7 @@ void Menu::exec() { if (!vm.isInitialized()) compile(); - vm.Run(0xFFFF,0); + vm.Run(false,false,0); showInstr(); } @@ -1374,7 +1463,7 @@ void Menu::trace() { if (!vm.isInitialized()) compile(); - vm.Run(vm.getNextInstr(),0); + vm.Run(true,false,0); showInstr(); } @@ -1382,7 +1471,7 @@ void Menu::step() { if (!vm.isInitialized()) compile(); - vm.Run(vm.getNextInstr(),0); + vm.Run(true,true,0); showInstr(); } diff --git a/ia86.h b/ia86.h index 5a297a3..2fd507c 100644 --- a/ia86.h +++ b/ia86.h @@ -139,7 +139,7 @@ struct Code struct Unasm { - std::vector> src; + std::vector> src; std::vector pos; }; @@ -199,14 +199,14 @@ class InstructionWindow final : public finalcut::FDialog // Disable copy assignment operator (=) InstructionWindow& operator = (const InstructionWindow&) = delete; // Method - std::vector> get(); - void set(std::vector> src); + std::vector> get(); + void set(std::vector> src); void clear(); void setmark(int index); int getsize(); private: // Method - std::vector> content; + std::vector> content; void initLayout() override; void adjustSize() override; // Data members @@ -263,50 +263,51 @@ class TextWindow final : public finalcut::FDialog finalcut::FTextView scrolltext{this}; }; +class Menu; + class Desassembler { public: - Desassembler(TextWindow *log); + Desassembler(Menu *widget); void Desassemble(uint8_t *content, uint32_t address,uint32_t size, Unasm *unasm); private: csh handle; cs_insn *insn; int err; - TextWindow *log; + Menu *widget; TextEditWindow *edit; size_t srcsize; size_t codesize; - std::vector> src; + std::vector> src; unsigned char *src_char = new unsigned char[64*1024]; }; class Assembler { public: - Assembler(TextWindow *log); + Assembler(Menu *widget); void Assemble(Code *code); std::vector MultiAssemble(std::string source,uint32_t address); private: ks_engine *ks; ks_err err; int err2; - TextWindow *log; + Menu *widget; TextEditWindow *edit; }; class VMEngine { public: - VMEngine(TextWindow *log); + VMEngine(Menu *widget); void Configure(State *init, std::string code); void Halt(); void Unconfigure(); - uint32_t getNextInstr(); uint32_t getCurrent(); - void Run(uint32_t end,uint64_t timeout); + void Run(bool astep, bool acall, uint64_t timeout); std::string getFlags(); std::string getRegs(); - std::vector> getInstr(int segment, int address,int size); + std::vector> getInstr(int segment, int address,int size); void SetMem(Code *code); void SetRegs(State *init); std::string getRam(int segment, int address,int lines, int linesize); @@ -314,6 +315,7 @@ class VMEngine bool isExecuted(); bool isInitialized(); void setRights(int rights); + void ClearScreen(); int getLine(); uint32_t getEIP(); uint16_t getCS(); @@ -324,8 +326,6 @@ class VMEngine int rights; void Init(); void Close(); - bool executed=false; - bool initialized=false; uc_engine *uc; uc_err err; int bufferaddress; @@ -333,9 +333,9 @@ class VMEngine uint8_t *code; uLong crc,crc_old; std::vector mcode; - TextWindow *log; - Assembler asmer{log}; - Desassembler unasmer{log}; + Menu *widget; + Assembler asmer{widget}; + Desassembler unasmer{widget}; }; class Menu final : public finalcut::FDialog @@ -351,6 +351,8 @@ class Menu final : public finalcut::FDialog Menu& operator = (const Menu&) = delete; // Methods void loadLevel(); + void tolog(std::string str); + void SetScreen(uint16_t x, uint16_t y, char value); TextWindow log{this}; private: void onTimer (finalcut::FTimerEvent*) override; @@ -370,6 +372,7 @@ class Menu final : public finalcut::FDialog void about(); void mini(); void maxi(); + void ClearScreen(); void AdjustWindows(); void initWindows(); void initLayout() override; @@ -415,7 +418,7 @@ class Menu final : public finalcut::FDialog TextWindow screen{this}; TextEditWindow edit{this}; ScenarioWindow scenar{this}; - VMEngine vm{&log}; + VMEngine vm{this}; }; diff --git a/scenarios.json b/scenarios.json index 145f684..3c26629 100644 --- a/scenarios.json +++ b/scenarios.json @@ -9,6 +9,7 @@ "niveau_code" : "mov ax,0x545 inc dx mov esi,0x44440234 +syscall hlt jmp 0x14D .org 0x8D @@ -58,15 +59,37 @@ mov es,ax "niveau_tutoriel" : "Ceci vous...", "niveau_code" : "mov ax,0x545 _pour: -inc dx -lea ebx,[_pour] +lea si,[msg] +call show +int 21 +hlt + +show: +push ax +push es +push di +push cx +mov ax,0xB800 +mov es,ax +mov di,(80*2+40)*2 +mov cx,16 +mov al,0 +boucle: +movsb +stosb +dec cx +cmp cx,0 +jnz boucle +pop cx +pop di +pop es +pop ax +ret + +msg: db 'c','e','c','i',' ','e','s','t',' ','u','n',' ','t','e','s','t',0 -.org 0x9000 -_pour: -db 0x00 -lea eax,[_pour] -mov esi,0x44441234 - .org 0x3002 + + .org 0x1000 hlt", "niveau_droits" : 10, "niveau_initial" :