Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1.  
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <alloca.h>
  6. #include <malloc.h>
  7. #include <setjmp.h>
  8. #include <envz.h>
  9.  
  10. #include <sys/kos_io.h>
  11.  
  12. #include "list.h"
  13. #include "pe.h"
  14.  
  15. #define unlikely(x)     __builtin_expect(!!(x), 0)
  16.  
  17. //#define DBG(format,...) printf(format,##__VA_ARGS__)
  18.  
  19. #define DBG(format,...)
  20.  
  21.  
  22. void      __fastcall init_loader(void *libc_image);
  23. void*     __fastcall create_image(void *raw);
  24. int       __fastcall link_image(void *img_base);
  25. int       __fastcall do_exec(uint32_t my_app, uint32_t *params);
  26.  
  27.  
  28. extern char* __appenv;
  29. extern int   __appenv_size;
  30.  
  31. typedef struct tag_module module_t;
  32.  
  33. struct app_hdr
  34. {
  35.     char  banner[8];
  36.     int   version;
  37.     int   start;
  38.     int   iend;
  39.     int   memsize;
  40.     int   stacktop;
  41.     char  *cmdline;
  42.     char  *path;
  43. };
  44.  
  45. struct tag_module
  46. {
  47.     struct list_head list;
  48.  
  49.     char       *img_name;
  50.     char       *img_path;
  51.  
  52.     uint32_t    refcount;
  53.  
  54.     void       *start;
  55.     uint32_t    end;
  56.  
  57.     void       *entry;
  58.  
  59.     PIMAGE_NT_HEADERS32      img_hdr;
  60.     PIMAGE_SECTION_HEADER    img_sec;
  61.     PIMAGE_EXPORT_DIRECTORY  img_exp;
  62. };
  63.  
  64. typedef struct
  65. {
  66.     struct list_head list;
  67.     char *path;
  68.     int   path_len;
  69. }dll_path_t;
  70.  
  71. module_t* load_module(const char *name);
  72.  
  73. LIST_HEAD(dll_list);
  74. LIST_HEAD(path_list);
  75.  
  76. static module_t libc_dll;
  77. static char libc_name[] = "libc.dll";
  78. static char libc_path[] = "/sys/lib/libc.dll";
  79.  
  80. static inline int IsPowerOf2(uint32_t val)
  81. {
  82.     if(val == 0)
  83.         return 0;
  84.     return (val & (val - 1)) == 0;
  85. }
  86.  
  87.  
  88. int validate_pe(void *raw, size_t raw_size, int is_exec)
  89. {
  90.     PIMAGE_DOS_HEADER     dos;
  91.     PIMAGE_NT_HEADERS32   nt;
  92.  
  93.     dos = (PIMAGE_DOS_HEADER)raw;
  94.  
  95.     if( !raw || raw_size < sizeof(IMAGE_DOS_HEADER) )
  96.         return 0;
  97.  
  98.     if( dos->e_magic != IMAGE_DOS_SIGNATURE || dos->e_lfanew <= 0)
  99.         return 0;
  100.  
  101.     nt =  MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew);
  102.  
  103.     if( (uint32_t)nt < (uint32_t)raw)
  104.         return 0;
  105.  
  106.     if(nt->Signature != IMAGE_NT_SIGNATURE)
  107.         return 0;
  108.  
  109.     if(nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
  110.         return 0;
  111.  
  112.     if(is_exec && (nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
  113.         return 0;
  114.  
  115.     if(nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  116.         return 0;
  117.  
  118.     if( is_exec && nt->OptionalHeader.ImageBase != 0)
  119.         return 0;
  120.  
  121.     if(nt->OptionalHeader.SectionAlignment < 4096)
  122.     {
  123.         if(nt->OptionalHeader.FileAlignment != nt->OptionalHeader.SectionAlignment)
  124.             return 0;
  125.     }
  126.     else if(nt->OptionalHeader.SectionAlignment < nt->OptionalHeader.FileAlignment)
  127.         return 0;
  128.  
  129.     if(!IsPowerOf2(nt->OptionalHeader.SectionAlignment) ||
  130.        !IsPowerOf2(nt->OptionalHeader.FileAlignment))
  131.         return 0;
  132.  
  133.     if(nt->FileHeader.NumberOfSections > 96)
  134.         return 0;
  135.  
  136.     return 1;
  137. }
  138.  
  139.  
  140. void __fastcall init_loader(void *libc_image)
  141. {
  142.  
  143.     PIMAGE_DOS_HEADER        dos;
  144.     PIMAGE_NT_HEADERS32      nt;
  145.     PIMAGE_EXPORT_DIRECTORY  exp;
  146.  
  147.     struct   app_hdr *header;
  148.  
  149.     dll_path_t *path;
  150.     int len;
  151.     char *p;
  152.  
  153.     if(__appenv_size)
  154.     {
  155.         char *env;
  156.         env = envz_get(__appenv, __appenv_size, "PATH");
  157.         if( env )
  158.         {
  159.             while( *env )
  160.             {
  161.                 p = env;
  162.                 while(*p)
  163.                 {
  164.                     if( *p == 0x0D)
  165.                         break;
  166.                     else if( *p == 0x0A)
  167.                         break;
  168.                     else if( *p == ':')
  169.                         break;
  170.                     p++;
  171.                 };
  172.                 len = p-env;
  173.                 if(len)
  174.                 {
  175.                     char *p1;
  176.  
  177.                     p1 = (char*)malloc(len+1);
  178.                     memcpy(p1, env, len);
  179.                     p1[len]=0;
  180.  
  181.                     path = (dll_path_t*)malloc(sizeof(dll_path_t));
  182.                     INIT_LIST_HEAD(&path->list);
  183.                     path->path = p1;
  184.                     path->path_len = len;
  185.                     DBG("add libraries path %s\n", path->path);
  186.                     list_add_tail(&path->list, &path_list);
  187.                 };
  188.                 if(*p == ':')
  189.                 {
  190.                     env = p+1;
  191.                     continue;
  192.                 }
  193.                 else break;
  194.             };
  195.         };
  196.     };
  197.  
  198.     header = (struct app_hdr*)NULL;
  199.  
  200.     len = strrchr(header->path, '/') - header->path+1;
  201.     p = (char*)malloc(len+1);
  202.     memcpy(p, header->path, len);
  203.     p[len]=0;
  204.  
  205.     path = (dll_path_t*)malloc(sizeof(dll_path_t));
  206.     INIT_LIST_HEAD(&path->list);
  207.     path->path = p;
  208.     path->path_len = len;
  209.     DBG("add libraries path %s\n", path->path);
  210.     list_add_tail(&path->list, &path_list);
  211.  
  212.  
  213. #if 0
  214.     path = (dll_path_t*)malloc(sizeof(dll_path_t));
  215.     INIT_LIST_HEAD(&path->list);
  216.     path->path = "/sys/lib/";
  217.     path->path_len = 9;                           /* FIXME */
  218.     DBG("add libraries path %s\n", path->path);
  219.     list_add_tail(&path->list, &path_list);
  220. #endif
  221.  
  222.     INIT_LIST_HEAD(&libc_dll.list);
  223.  
  224.     libc_dll.img_name = libc_name;
  225.     libc_dll.img_path = libc_path;
  226.  
  227.     libc_dll.refcount = 1;
  228.  
  229.     dos =  (PIMAGE_DOS_HEADER)libc_image;
  230.     nt  =  MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew);
  231.     exp =  MakePtr(PIMAGE_EXPORT_DIRECTORY, libc_image,
  232.                    nt->OptionalHeader.DataDirectory[0].VirtualAddress);
  233.  
  234.     libc_dll.start = libc_image;
  235.     libc_dll.end   = MakePtr(uint32_t,libc_image, nt->OptionalHeader.SizeOfImage);
  236.  
  237.     libc_dll.img_hdr  = nt;
  238.     libc_dll.img_sec  = MakePtr(PIMAGE_SECTION_HEADER,nt, sizeof(IMAGE_NT_HEADERS32));
  239.     libc_dll.img_exp  = MakePtr(PIMAGE_EXPORT_DIRECTORY,libc_image,
  240.                         nt->OptionalHeader.DataDirectory[0].VirtualAddress);
  241.  
  242.     list_add_tail(&libc_dll.list, &dll_list);
  243. };
  244.  
  245. const module_t* find_module(const char *name)
  246. {
  247.     module_t* mod;
  248.  
  249.     list_for_each_entry(mod, &dll_list, list)
  250.     {
  251.         if( !strncmp(name, mod->img_name, 16))
  252.             return mod;
  253.     };
  254.  
  255.     return load_module(name);
  256. };
  257.  
  258. static inline void sec_copy(void *dst, void *src, size_t len)
  259. {
  260.     __asm__ __volatile__ (
  261.     "shrl $2, %%ecx         \n\t"
  262.     "rep movsl"
  263.     :
  264.     :"c"(len),"S"(src),"D"(dst)
  265.     :"cc");
  266.     __asm__ __volatile__ (
  267.     ""
  268.     :::"ecx","esi","edi");
  269. };
  270.  
  271. static inline void *user_alloc(size_t size)
  272. {
  273.     void *val;
  274.     __asm__ __volatile__(
  275.     "int $0x40"
  276.     :"=eax"(val)
  277.     :"a"(68),"b"(12),"c"(size));
  278.     return val;
  279. }
  280.  
  281. void* __fastcall create_image(void *raw)
  282. {
  283.     PIMAGE_DOS_HEADER     dos;
  284.     PIMAGE_NT_HEADERS32   nt;
  285.     PIMAGE_SECTION_HEADER img_sec;
  286.  
  287.     void  *img_base;
  288.     uint32_t  sec_align;
  289.     int    i;
  290.  
  291.     dos = (PIMAGE_DOS_HEADER)raw;
  292.     nt =  MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew);
  293.  
  294.     img_base = user_alloc(nt->OptionalHeader.SizeOfImage);
  295.  
  296.     if(unlikely(img_base == NULL))
  297.         return 0;
  298.  
  299.     sec_copy(img_base, raw, nt->OptionalHeader.SizeOfHeaders);
  300.  
  301.     img_sec = MakePtr(PIMAGE_SECTION_HEADER, nt, sizeof(IMAGE_NT_HEADERS32));
  302.  
  303.     sec_align = nt->OptionalHeader.SectionAlignment;
  304.  
  305.     for(i=0; i< nt->FileHeader.NumberOfSections; i++)
  306.     {
  307.         void *src_ptr;
  308.         void *dest_ptr;
  309.         size_t   sec_size;
  310.  
  311.         if ( img_sec->SizeOfRawData && img_sec->PointerToRawData )
  312.         {
  313.             src_ptr  = MakePtr(void*, raw, img_sec->PointerToRawData);
  314.             dest_ptr = MakePtr(void*, img_base, img_sec->VirtualAddress);
  315.             sec_copy(dest_ptr, src_ptr, img_sec->SizeOfRawData);
  316.         };
  317.  
  318.         img_sec++;
  319.     };
  320.  
  321.     if(nt->OptionalHeader.DataDirectory[5].Size)
  322.     {
  323.         PIMAGE_BASE_RELOCATION reloc;
  324.  
  325.         uint32_t delta = (uint32_t)img_base - nt->OptionalHeader.ImageBase;
  326.  
  327.         reloc = MakePtr(PIMAGE_BASE_RELOCATION, img_base,
  328.                         nt->OptionalHeader.DataDirectory[5].VirtualAddress);
  329.  
  330.         while ( reloc->SizeOfBlock != 0 )
  331.         {
  332.             uint32_t  cnt;
  333.             uint16_t *entry;
  334.             uint16_t  reltype;
  335.             uint32_t  offs;
  336.  
  337.             cnt = (reloc->SizeOfBlock - sizeof(*reloc))/sizeof(uint16_t);
  338.             entry = MakePtr( uint16_t*, reloc, sizeof(*reloc) );
  339.  
  340.             for ( i=0; i < cnt; i++ )
  341.             {
  342.                 uint16_t *p16;
  343.                 uint32_t *p32;
  344.  
  345.                 reltype = (*entry & 0xF000) >> 12;
  346.                 offs = (*entry & 0x0FFF) + reloc->VirtualAddress;
  347.                 switch(reltype)
  348.                 {
  349.                     case 1:
  350.                         p16 = MakePtr(uint16_t*, img_base, offs);
  351.                         *p16+= (uint16_t)(delta>>16);
  352.                         break;
  353.                     case 2:
  354.                         p16 = MakePtr(uint16_t*, img_base, offs);
  355.                         *p16+= (uint16_t)delta;
  356.                         break;
  357.                     case 3:
  358.                         p32 = MakePtr(uint32_t*, img_base, offs);
  359.                         *p32+= delta;
  360.                 }
  361.                 entry++;
  362.             }
  363.             reloc = MakePtr(PIMAGE_BASE_RELOCATION, reloc,reloc->SizeOfBlock);
  364.         }
  365.     };
  366.     return img_base;
  367. };
  368.  
  369. int __fastcall link_image(void *img_base)
  370. {
  371.     static jmp_buf loader_env;
  372.     static recursion = -1;
  373.  
  374.     PIMAGE_DOS_HEADER     dos;
  375.     PIMAGE_NT_HEADERS32   nt;
  376.     int warn = 0;
  377.  
  378.     recursion++;
  379.     if( !recursion )
  380.     {
  381.         if( unlikely(setjmp(loader_env) != 0))
  382.         {
  383.             recursion = -1;
  384.             return 0;
  385.         };
  386.     };
  387.  
  388.     dos = (PIMAGE_DOS_HEADER)img_base;
  389.     nt =  MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew);
  390.  
  391.     if(nt->OptionalHeader.DataDirectory[1].Size)
  392.     {
  393.         PIMAGE_IMPORT_DESCRIPTOR imp;
  394.  
  395.         imp = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, img_base,
  396.                       nt->OptionalHeader.DataDirectory[1].VirtualAddress);
  397.  
  398.         while ( imp->Name )
  399.         {
  400.             PIMAGE_DOS_HEADER        expdos;
  401.             PIMAGE_NT_HEADERS32      expnt;
  402.             PIMAGE_EXPORT_DIRECTORY  exp;
  403.             PIMAGE_THUNK_DATA32      thunk;
  404.  
  405.             void       **iat;
  406.             char       *libname;
  407.             uint32_t   *exp_functions;
  408.             uint16_t   *exp_ordinals;
  409.             char      **exp_names;
  410.  
  411.             const module_t *api;
  412.  
  413.             libname=MakePtr(char*,imp->Name, img_base);
  414.  
  415.             DBG("import from %s\n",libname);
  416.  
  417.             api = find_module(libname);
  418.             if(unlikely(api == NULL))
  419.             {
  420.                 printf("library %s not found\n", libname);
  421.                 longjmp(loader_env, 1);
  422.             }
  423.  
  424.             iat = MakePtr(void**,imp->FirstThunk, img_base);
  425.  
  426.             if(imp->OriginalFirstThunk !=0 )
  427.             {
  428.                 thunk = MakePtr(PIMAGE_THUNK_DATA32,imp->OriginalFirstThunk, img_base);
  429.             }
  430.             else
  431.             {
  432.                 thunk = MakePtr(PIMAGE_THUNK_DATA32,imp->FirstThunk, img_base);
  433.             };
  434.  
  435.             exp = api->img_exp;
  436.  
  437.             exp_functions = MakePtr(uint32_t*,exp->AddressOfFunctions,api->start);
  438.             exp_ordinals = MakePtr(uint16_t*,  exp->AddressOfNameOrdinals,api->start);
  439.             exp_names = MakePtr(char**, exp->AddressOfNames,api->start);
  440.  
  441.             while ( thunk->u1.AddressOfData != 0 )
  442.             {
  443.                 PIMAGE_IMPORT_BY_NAME imp_name;
  444.  
  445.                 if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
  446.                 {
  447. //                    ordinal = (*func_list) & 0x7fffffff;
  448. //                   *ImportAddressList = LdrGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
  449. //                    if ((*ImportAddressList) == NULL)
  450. //                    {
  451. //                        DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
  452. //                        RtlpRaiseImportNotFound(NULL, Ordinal, &ImportedModule->FullDllName);
  453. //                        return STATUS_ENTRYPOINT_NOT_FOUND;
  454. //                    }
  455.                 }
  456.                 else
  457.                 {
  458.                     char *export_name;
  459.                     uint16_t   ordinal;
  460.                     void      *function;
  461.                     uint32_t   minn;
  462.                     uint32_t   maxn;
  463.  
  464.                     imp_name = MakePtr(PIMAGE_IMPORT_BY_NAME,
  465.                                   thunk->u1.AddressOfData, img_base);
  466.                     *iat = NULL;
  467.  
  468.                     DBG("import %s", imp_name->Name);
  469.  
  470.                     if(imp_name->Hint < exp->NumberOfNames)
  471.                     {
  472.                         export_name = MakePtr(char*,exp_names[imp_name->Hint],
  473.                                               api->start);
  474.                         if(strcmp(imp_name->Name, export_name) == 0)
  475.                         {
  476.                             ordinal = exp_ordinals[imp_name->Hint];
  477.                             function = MakePtr(void*,exp_functions[ordinal], api->start);
  478.                             if((uint32_t)function >= (uint32_t)exp)
  479.                             {
  480.                                 printf("forward %s\n", function);
  481.                                 warn=1;
  482.                             }
  483.                             else
  484.                             {
  485.                                 DBG(" \t\tat %x\n", function);
  486.                                 *iat = function;
  487.                             };
  488.                             thunk++;  // Advance to next thunk
  489.                             iat++;
  490.                             continue;
  491.                         };
  492.                     };
  493.  
  494.  
  495.                     minn = 0;
  496.                     maxn = exp->NumberOfNames - 1;
  497.                     while (minn <= maxn)
  498.                     {
  499.                         int mid;
  500.                         int res;
  501.  
  502.                         mid = (minn + maxn) / 2;
  503.  
  504.                         export_name = MakePtr(char*,exp_names[mid],api->start);
  505.  
  506.                         res = strcmp(export_name, imp_name->Name);
  507.                         if (res == 0)
  508.                         {
  509.                             ordinal  = exp_ordinals[mid];
  510.                             function = MakePtr(void*,exp_functions[ordinal], api->start);
  511.  
  512.                             if((uint32_t)function >= (uint32_t)exp)
  513.                             {
  514.                                 printf("forward %s\n", function);
  515.                                 warn=1;
  516.                             }
  517.                             else
  518.                             {
  519.                                 DBG(" \t\tat %x\n", function);
  520.                                 *iat = function;
  521.                             };
  522.                             break;
  523.                         }
  524.                         else if (minn == maxn)
  525.                         {
  526.                             printf(" unresolved\n",imp_name->Name);
  527.                             warn=1;
  528.                             break;
  529.                         }
  530.                         else if (res > 0)
  531.                         {
  532.                             maxn = mid - 1;
  533.                         }
  534.                         else
  535.                         {
  536.                             minn = mid + 1;
  537.                         }
  538.                     };
  539.                 };
  540.                 thunk++;            // Advance to next thunk
  541.                 iat++;
  542.             }
  543.             imp++;  // advance to next IMAGE_IMPORT_DESCRIPTOR
  544.         };
  545.     };
  546.  
  547.     recursion--;
  548.  
  549.     if ( !warn )
  550.         return 1;
  551.     else
  552.         return 0;
  553. }
  554.  
  555. void* get_entry_point(void *raw)
  556. {
  557.     PIMAGE_DOS_HEADER     dos;
  558.     PIMAGE_NT_HEADERS32   nt;
  559.  
  560.     dos = (PIMAGE_DOS_HEADER)raw;
  561.     nt =  MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew);
  562.  
  563.     return  MakePtr(void*, raw, nt->OptionalHeader.AddressOfEntryPoint);
  564. }
  565.  
  566.  
  567. module_t* load_module(const char *name)
  568. {
  569.     char *path;
  570.     int   len;
  571.  
  572.     len = strlen(name);
  573.  
  574.     dll_path_t *dllpath;
  575.  
  576.     list_for_each_entry(dllpath, &path_list, list)
  577.     {
  578.         PIMAGE_DOS_HEADER        dos;
  579.         PIMAGE_NT_HEADERS32      nt;
  580.         PIMAGE_EXPORT_DIRECTORY  exp;
  581.  
  582.         module_t *module;
  583.         void     *raw_img;
  584.         size_t    raw_size;
  585.         void     *img_base;
  586.  
  587.         path = alloca(len+dllpath->path_len+1);
  588.         memcpy(path, dllpath->path, dllpath->path_len);
  589.  
  590.         memcpy(path+dllpath->path_len, name, len);
  591.         path[len+dllpath->path_len]=0;
  592.  
  593.         raw_img = load_file(path, &raw_size);
  594.         if(raw_img == NULL)
  595.             continue;
  596.  
  597.         if( validate_pe(raw_img, raw_size, 0) == 0)
  598.         {
  599.             printf("invalide module %s\n", path);
  600.             user_free(raw_img);
  601.             continue;
  602.         };
  603.  
  604.         img_base = create_image(raw_img);
  605.         user_free(raw_img);
  606.  
  607.         if( unlikely(img_base == NULL) )
  608.         {
  609.             printf("cannot create image %s\n",path);
  610.             continue;
  611.         };
  612.  
  613.         module = (module_t*)malloc(sizeof(module_t));
  614.  
  615.         if(unlikely(module == NULL))
  616.         {
  617.             printf("%s epic fail: no enough memory\n",__FUNCTION__);
  618.             user_free(img_base);
  619.             return 0;
  620.         }
  621.  
  622.         INIT_LIST_HEAD(&module->list);
  623.  
  624.         module->img_name = strdup(name);
  625.         module->img_path = strdup(path);
  626.         module->start    = img_base;
  627.         module->entry    = get_entry_point(img_base);
  628.         module->refcount = 1;
  629.  
  630.         dos =  (PIMAGE_DOS_HEADER)img_base;
  631.         nt  =  MakePtr( PIMAGE_NT_HEADERS32, dos, dos->e_lfanew);
  632.         exp =  MakePtr(PIMAGE_EXPORT_DIRECTORY, img_base,
  633.                    nt->OptionalHeader.DataDirectory[0].VirtualAddress);
  634.  
  635.         module->end   = MakePtr(uint32_t,img_base, nt->OptionalHeader.SizeOfImage);
  636.  
  637.         module->img_hdr  = nt;
  638.         module->img_sec  = MakePtr(PIMAGE_SECTION_HEADER,nt, sizeof(IMAGE_NT_HEADERS32));
  639.         module->img_exp  = MakePtr(PIMAGE_EXPORT_DIRECTORY, img_base,
  640.                            nt->OptionalHeader.DataDirectory[0].VirtualAddress);
  641.  
  642.         list_add_tail(&module->list, &dll_list);
  643.  
  644.         if( link_image(img_base))
  645.             return module;
  646.         return NULL;
  647.     };
  648.  
  649.     return NULL;
  650. };
  651.  
  652.  
  653.