// // Mister Dinam0xki present // // SFFA-baby: Scripted File Format Analyser // // well, this program was coded by someone that had C++ teached by // herm, not professional poeple, well, it's a bit lame as code, as // it's one of my first c apps, I used this stupid fstream structure, // the rest is bunch of ideas // // After writing several file analyser, I saw that many things were // similar, After the third analyzer wrote, I tought it was enough, // and then, in one night, I build this small apps // The main idea is that you could use one unique routine and an // external file that explain how you have to handle with the unique // routine // // The rest is just brain juice, well the sffa is still in baby state // the processor have 256 unsigned long that the script can acess, // there's 64 integer for internal "for" handle // for much newbie than me, an unsigned long is simple a 32 bit value // // please, pay attention, the script is case sensible // // you can play with these long: // // function: set #long_handle value -> put value in #long_handle // add #h1 #h2 #h3 -> put #h1 + #h2 in #h3 // // well, you can then play with the file being analyzed with this: // // seek #h1 -> go to #h1 // // then you send to the output using these following functions // // skipline -> pass one line // put char(*) -> write a char in the buffer // tchar char(*) -> write char followed by a null // terminated car to buffer // char #val1 char(*) -> read (#val1) bytes, write // char write buffer // dword char(*) ? type val // // this function read a dword, write char to output, wirte " = " // write the dword value in the type format, type is VAL (dec) // HEX or CHAR, then this value is send to #val // // word char ? type val do basically the same thing // // the ? is an optional type value,don't need to put it,you have // just 4 argument to this, but if you put CASE you have five // exemple: dword value_one CASE HEX 5 // hi 1 // hello 2 // caca 3 // endcase // // then if the dword = 1, it will put "(hi)" // // * well, you can't define space in char, but they are accepted // in the output, so you change space by the "_" char, it will // be swaped to a space // // flag char dword (or word) will load a dword // packet xxx (load xxx bit in the dword) // bit 0 blabla #val (if bit 0=1 put char blabla // endflag and #val=1) // // and then you have programming functions // // if #val != (or ==) value if #val != #value execute // ... the following // endif // // for #val #val2 char char is for title // note: #val2 is a forhandle then, it will do #val1 time the... // note: same things // ... // endfor #val2 (reapeat the for) // // ends exit the script // // // well, this is a starting, I included a cab analyser and a PE header // analyser, I will improve seriously this apps in the future // // oh yes, how to use this program: // // filean scriptfile infile outfil // // exemple: this should analyse microsoft cabinet file: // // cut here - - - - - /* skipline put _Cabinet_file_analyzer_by_STAR0_[iKx] skipline skipline put Cab_Header: skipline dword Cab_signature CHAR 1 if 1 != 0x4643534D put invalid_file ends endif dword reserved1 DEC 0 dword Cabinet_size DEC 0 dword reserved2 DEC 0 dword Directory_offset DEC 1 dword reserved3 DEC 0 word Version HEX 0 word Number_of_folder(s) DEC 2 word Number_of_file(s) DEC 3 flag flags word packet 16 bit 1 previous 0 bit 2 next 0 bit 3 reserve 99 endflag word Cabinet_ID HEX 0 word Cabinet_disk_number HEX 0 if 99 == 1 put reserved_cab_format ends endif skipline skipline for 2 9 Cabinet_Folders: skipline dword Cabinet_Start HEX 0 word #_Data_Block DEC 0 word Compression_type CASE HEX 5 no_compression 0 endcase endfor 9 seek 1 skipline skipline for 3 8 Cabinet_File_Folder: skipline dword Original_file_size DEC 0 dword Original_file_offset DEC 0 word Folder_Index CASE DEC 0 continued_from_prev 0xFFFD continued_to_next 0xFFFE continued_prev_and_next 0xFFFF endcase dword Time_data_stamp HEX 0 word File_attribute HEX 0 tchar Filename endfor 8 ends */ // exemple: this should give various info about PE headers // // cut here - - - - - /* skipline put _Portable_executable_file_analyzer_by_STAR0_[iKx] skipline skipline word MZ_magic_value CHAR 0 if 0 != 0x5A4D put error:_not_an_exe_file ends endif set 0 0x3C seek 0 dword Extended_header_offset HEX 99 seek 99 dword Extended_header_type CHAR 0 if 0 != 0x4550 put error:_not_a_pe_file ends endif word Machine_Type CASE HEX 0 I386 0x14C I486 0x14D I586 0x14E R3000(big_endian) 0x160 R3000 0x162 R4000 0x166 R10000 0x168 Dec_Alpha_AXP 0x184 IBM_Power_PC 0x1F0 endcase word Number_of_section DEC 5 dword Time_data_stamp HEX 0 dword Symbol_table_offset HEX 0 dword Number_of_symbol DEC 0 word Size_of_optional_header DEC 98 flag Flags word packet 16 bit 0 NoReloc 0 bit 1 NoLineinfo 0 bit 3 NoSymbol 0 bit 4 AWSTRIM 0 bit 7 litend 0 bit 8 32bit 0 bit 9 NoDebug 0 bit 10 Rmvdisk 0 bit 11 NoNetRun 0 bit 12 Driver 0 bit 13 DLLSet 0 bit 14 NoMultiproc 0 bit 15 Bigend01 0 endflag skipline word Optional_header_magic HEX 0 word linker_version HEX 0 dword code_size DEC 0 dword Initialized_data DEC 0 dword Uninitialized_data DEC 0 dword Entrypoint HEX 0 dword Code_offset HEX 0 dword Data_offset HEX 0 dword Image_Base HEX 0 dword Section_alignment HEX 0 dword File_alignment HEX 0 dword Os_version HEX 0 dword Image_version HEX 0 dword Subsystem_version HEX 0 dword Win32_version HEX 0 dword Image_Size HEX 0 dword Header_size HEX 0 dword PE_Checksum HEX 0 word Subsystem CASE DEC 0 Native 1 Windows_GUI 2 Windows_CUI 3 OS2_CUI 4 POSIX_CUI 5 else null endcase flag Dll_flags word packet 16 bit 0 process_attachments 0 bit 1 process_detachments 0 bit 2 thread_attachments 0 bit 3 thread_detachments 0 endflag dword Stack_reserved_size DEC 0 dword Stack_commited_size DEC 0 dword Heap_reserved_size DEC 0 dword Heap_commited_size DEC 0 dword Loader_flags(undoc) HEX 0 dword Number_of_RVA_entries DEC 0 dword Export_table_RVA HEX 0 dword Export_table_size DEC 0 dword Import_table_RVA HEX 15 dword Import_table_size DEC 0 dword Ressource_table_RVA HEX 0 dword Ressource_table_size DEC 0 dword Security_table_RVA HEX 0 dword Security_table_size DEC 0 dword Relocation_table_RVA HEX 0 dword Relocation_table_size DEC 0 dword Debug_table_RVA HEX 0 dword Debug_table_size DEC 0 dword Copyright_string_RVA HEX 0 dword Copyright_string_size DEC 0 dword Global_Machine_pointer_RVA HEX 0 dword Global_Machine_pointer_size DEC 0 dword TLS_Directory_RVA HEX 0 dword TLS_Directory_size DEC 0 dword Load_Configuration_RVA HEX 0 dword Load_Configuration_size DEC 0 dword Bound_Import_RVA HEX 0 dword Bound_Import_size DEC 0 set 96 24 add 99 98 97 add 97 96 95 seek 95 skipline skipline set 94 8 for 5 9 Sections: skipline char 94 Name dword Virtual_Size DEC 13 dword Section_RVA HEX 12 dword Physical_Size DEC 0 dword Section_Offset HEX 0 dword Relocation_Pointer HEX 0 dword Ptr_line_number HEX 0 dword Number_of_relocations DEC 0 flag Flags dword packet 32 bit 5 code 0 bit 6 init 0 bit 7 uninit 0 bit 9 link 0 bit 18 locked 0 bit 25 discarded 0 bit 28 shared 0 bit 29 exec 0 bit 30 read 0 bit 31 write 0 endflag endfor 9 ends */ // Then, here's an exemple of the output /* Portable executable file analyzer by STAR0 [iKx] MZ magic value = MZ Extended header offset = 000000B0h Extended header type = PE Machine Type = 014Ch (I386) Number of section = 4 Time data stamp = 36349F6Dh Symbol table offset = 00000000h Number of symbol = 0 Size of optional header = 224 Flags = NoReloc NoLineinfo NoSymbol 32bit Optional header magic = 010Bh linker version = 0A05h code size = 10240 Initialized data = 16896 Uninitialized data = 0 Entrypoint = 00001000h Code offset = 00001000h Data offset = 00004000h Image Base = 00400000h Section alignment = 00001000h File alignment = 00000200h Os version = 00000004h Image version = 00000000h Subsystem version = 00000004h Win32 version = 00000000h Image Size = 0000A000h Header size = 00000400h PE Checksum = 00000000h Subsystem = 2 (Windows GUI) Dll_flags = null Stack reserved size = 1048576 Stack commited size = 4096 Heap reserved size = 1048576 Heap commited size = 4096 Loader flags(undoc) = 00000000h Number of RVA entries = 16 Export table RVA = 00000000h Export table size = 0 Import table RVA = 000042C4h Import table size = 80 Ressource table RVA = 00009000h Ressource table size = 1288 Security table RVA = 00000000h Security table size = 0 Relocation table RVA = 00000000h Relocation table size = 0 Debug table RVA = 00000000h Debug table size = 0 Copyright string RVA = 00000000h Copyright string size = 0 Global Machine pointer RVA = 00000000h Global Machine pointer size = 0 TLS Directory RVA = 00000000h TLS Directory size = 0 Load Configuration RVA = 00000000h Load Configuration size = 0 Bound Import RVA = 00000000h Bound Import size = 0 Sections: Name: .text Virtual Size = 10070 Section RVA = 00001000h Physical Size = 10240 Section Offset = 00000400h Relocation Pointer = 00000000h Ptr line number = 00000000h Number of relocations = 0 Flags = code exec read Name: .rdata Virtual Size = 1268 Section RVA = 00004000h Physical Size = 1536 Section Offset = 00002C00h Relocation Pointer = 00000000h Ptr line number = 00000000h Number of relocations = 0 Flags = init read Name: .data Virtual Size = 13696 Section RVA = 00005000h Physical Size = 5120 Section Offset = 00003200h Relocation Pointer = 00000000h Ptr line number = 00000000h Number of relocations = 0 Flags = init read write Name: .rsrc Virtual Size = 1288 Section RVA = 00009000h Physical Size = 1536 Section Offset = 00004600h Relocation Pointer = 00000000h Ptr line number = 00000000h Number of relocations = 0 Flags = init read */ //#include "stdafx.h" // well, it's just need by visual c++, use a pseudo one #include "fstream.h" #include "fcntl.h" #include "sys/types.h" #include "io.h" #include "stdio.h" typedef unsigned char BYTE; typedef unsigned char WORD[2]; typedef unsigned char DWORD[4]; void hex(unsigned long number, char blabla[9]) { blabla[8] = 'h'; blabla[9] = 0; unsigned long tempv, longv=number; for (int a=0; a < 8; a++) { tempv= longv & -16; tempv= longv-tempv; longv= longv-tempv; longv= longv/16; if (tempv < 10) blabla[8-a-1] = tempv+'0'; else blabla[8-a-1]= tempv+'A'-10; } } bool TestChar(char p1[], char p2[]) { for(int i=0; p2[i] != 0; i++) if (p2[i] != p1[i]) return false; return true; } void SetSpace(char p1[]) { for(int i=0; p1[i] != 0; i++) if (p1[i] == '_') p1[i] = ' '; } bool BInv(bool c1) { if (c1 == true) return false; return true; } int analisW(unsigned char numerica[2]) { unsigned int restype; restype = ((numerica[1])*256)+numerica[0]; return restype; } long analisDW(unsigned char mytype[4]) { unsigned long restype; restype = (((((mytype[3] * 256)+mytype[2])*256)+mytype[1])*256)+mytype[0]; return restype; } int main(int argc, char **argv) { if (argc == 4) { ifstream direct(argv[1]); ofstream result(argv[3]); int handle = _open(argv[2], O_RDWR); unsigned long value[259]; if (handle == NULL) result << "file not open" << endl; else { int forhandle[64]; for (char directive[256];BInv(TestChar (directive,"ends")); ) { // here we test each commands if (TestChar (directive,"char")) { // we look for a char int val1; direct >> val1; char testv[255]; testv[value[val1]]=0; read (handle, &testv, value[val1]); // read the 1st direct >> directive; // arg bytes result << directive << ": " << testv << endl; // drop to output } if (TestChar (directive,"add")) { int val1, val2, val3; // add command direct >> val1 >> val2 >> val3; // value[val3] = value[val2] + value[val1]; } if (TestChar (directive,"set")) { int seekval; direct >> seekval; // set command unsigned long setval; direct >> setval; value[seekval] = setval; } if (TestChar (directive,"seek")) { int seekval; // seek command direct >> seekval; lseek (handle, value[seekval], SEEK_SET); } if (TestChar (directive,"tchar")) { direct >> directive; // terminated char SetSpace(directive); result << directive << ": "; char blue[2]; blue[1]=0; blue[0]=' '; for (; blue[0] != 0; ) { read (handle, &blue, 1); result << blue; // read untill we find a zero } // and drop to output result << endl; } if (TestChar (directive,"put")) { // put a char direct >> directive; SetSpace(directive); // convert "_" to space result << directive << endl; } if (TestChar (directive,"skipline")) // add a line to buffer result << endl; if (TestChar (directive,"dword")) // load a dword { direct >> directive; SetSpace(directive); result << directive << " = "; // drop the char + " = " unsigned char bla1[5]; char bla2[9]; // buffer for hex bla1[4]=0; read (handle, &bla1, 4); // read 4 bytes direct >> directive; // look if we have case int caseflag=0; if (TestChar(directive,"CASE")) { caseflag = 1; // set case flag direct >> directive; // load directive } if (TestChar (directive,"CHAR")) // drop to buffer result << bla1; // following the right // format if (TestChar (directive,"DEC")) result << analisDW(bla1); if (TestChar (directive,"HEX")) { hex (analisDW(bla1), bla2); result << bla2; } int val,valc; direct >> val; value[val] = analisDW(bla1); // set internal value = // read value if (caseflag == 1) { direct >> directive; // we got CASE int spaceflag=0; for(;BInv(TestChar (directive,"endcase"));direct >> directive) { if (BInv(TestChar (directive,"else"))) // if it's one of { // these put the char following direct >> valc; // the else if(value[val] == valc) { SetSpace(directive); result << " (" << directive << ")"; spaceflag = 1; } } else { direct >> directive; // else if (spaceflag == 0) // if it's else already? { SetSpace(directive); // and it's the correct value result << " (" << directive << ")"; // drop to buffer the char } } } } result << endl; } if (TestChar (directive,"word")) // well, it's approx { // the same structure than // dword direct >> directive; // with different buffer SetSpace(directive); // and subrouitne call result << directive << " = "; unsigned char bla1[5]; char bla2[9]; bla1[2]=0; bla1[3]=0; bla1[4]=0; read (handle, &bla1, 2); direct >> directive; int caseflag=0; if (TestChar(directive,"CASE")) { caseflag = 1; direct >> directive; } if (TestChar (directive,"CHAR")) result << bla1; if (TestChar (directive,"DEC")) result << analisW(bla1); if (TestChar (directive,"HEX")) { hex (analisW(bla1), bla2); char bla3[5]; for (int i=4; i < 10; i++) bla3[i-4]=bla2[i]; result << bla3; } int val, valc; direct >> val; value[val] = analisW(bla1); if (caseflag == 1) { direct >> directive; int spaceflag=0; for(;BInv(TestChar (directive,"endcase"));direct >> directive) { if (BInv(TestChar (directive,"else"))) { direct >> valc; if(value[val] == valc) { SetSpace(directive); result << " (" << directive << ")"; spaceflag = 1; } } else { direct >> directive; if (spaceflag == 0) { SetSpace(directive); result << " (" << directive << ")"; } } } } result << endl; } if (TestChar (directive,"if")) { direct >> value[257]; direct >> directive; direct >> value[258]; if (TestChar (directive,"!=")) // go to endif if cond not if (value[value[257]] == value[258]) // true for(;BInv(TestChar (directive,"endif")); direct >> directive); if (TestChar (directive,"==")) // do the same if (value[value[257]] != value[258]) for(;BInv(TestChar (directive,"endif")); direct >> directive); } if (TestChar (directive,"for")) // go search for a for { int fortest, fortest2; direct >> fortest >> fortest2; // save #val and forhandle if (value[fortest] != 0) // if needed for is not null { if (forhandle[fortest] == 0) // if #val null, skip for for (;BInv(TestChar (directive,"endfor")); direct >> directive); else { direct >> directive; SetSpace(directive); result << directive << endl; forhandle[fortest2] = value[fortest]; } } else // if for is null, skip for for (;BInv(TestChar (directive,"endfor")); direct >> directive); } if (TestChar (directive,"endfor")) // reached an endfor { int fortest=0,fortest2=1; // set flags direct >> fortest; // load fortest direct.seekg(0); for (;fortest != fortest2;) // watch that fortest is { // different from one or direct >> directive; // test if (TestChar (directive,"for")) // watch for a for { direct >> fortest2; // load the for handler direct >> fortest2; } } forhandle[fortest2]--; // decrement for handle if(forhandle[fortest2] == 0) // we reached end of for ? for (;BInv(TestChar (directive,"endfor"));direct >> directive); direct >> directive; // allright baby, skip endfor } // handle if (TestChar (directive,"flag")) // test flag command { direct >> directive; result << directive << " = "; unsigned char bla1[5]; for(int i = 0; i < 5; i++) bla1[i]=0; // zeroize the buffer direct >> directive; if (TestChar (directive,"word")) // load the word read (handle, &bla1, 2); if (TestChar (directive,"dword")) // or the dword read (handle, &bla1, 4); unsigned long valme = analisDW(bla1), valme1; // load int valde = 0; // the flag value direct >> directive; if (valme == 0) result << "null"; // if flags = 0 put "null" for (;BInv(TestChar (directive,"endflag")); direct >> directive) { if (TestChar (directive,"packet")) // got a packet directive { int packsize; direct >> packsize; unsigned long andvalue=0; valme1 = valme; valme = valme >> packsize; // load the packet valde += packsize; // valde will be used for } if (TestChar (directive,"bit")) // test bit directive { int shiftval; direct >> shiftval; int valtest = valme1 >> shiftval; // test bit value direct >> directive; // at position SetSpace(directive); if ((valtest%2) == 1) // if the bit is on result << directive << " "; direct >> shiftval; // then drop flag to output value[shiftval] = valtest; } } result << endl; // finish line } direct >> directive; // load the next directive } // (it crashed in the for } // structure misteriously) return 0; // finish! } else { cout << " SFFA-baby " << endl; cout << " please use this syntax: filan script input output " << endl; } }