//
// 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;
}
}
