Creating a Self-Extracting Executable

I want to be able to extract a resource file from my executable. I think that I've figured out how to access the data, but I don't know how to extract it. Here is what I have been able to do so far:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

int main()
{
    extern size_t files_data[] asm("_binary_files_tgz_start"); // Start of resource
    extern size_t files_data_size[] asm("_binary_files_tgz_size"); // Size of resource
    extern size_t files_data_end[] asm("_binary_files_tgz_end"); // End of resource
    
    for (size_t *byte = files_data; byte < files_data_end; ++byte)
    {
        cout << byte << endl;
    }
    
    return 0;
}


Output:
0x804a028
0x804a02c
0x804a030
0x804a034
0x804a038
0x804a03c
0x804a040
0x804a044
0x804a048
0x804a04c
0x804a050
0x804a054
0x804a058
0x804a05c
0x804a060
0x804a064
0x804a068
0x804a06c
0x804a070
0x804a074
0x804a078
0x804a07c
0x804a080
0x804a084
0x804a088
0x804a08c
0x804a090
0x804a094
0x804a098


Does anyone know a way to help me?
If this is windows, there are dedicated APIs for this, see "resources overview" on MSDN. If you are running another OS, one way is to embbed binary data directly as char[] array in your source code. You "extract" this as any other memory buffer.
This is a small C program for doing this, use it at your own risk:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// bin2c.c
//
// convert a binary file into a C source vector
//
// THE "BEER-WARE LICENSE" (Revision 3.1415):
// sandro AT sigala DOT it wrote this file. As long as you retain this notice you can do
// whatever you want with this stuff.  If we meet some day, and you think this stuff is
// worth it, you can buy me a beer in return.  Sandro Sigala
//
// syntax:  bin2c [-c] [-z] <input_file> <output_file>
//
//          -c    add the "const" keyword to definition
//          -z    terminate the array with a zero (useful for embedded C strings)
//
// examples:
//     bin2c -c myimage.png myimage_png.cpp
//     bin2c -z sometext.txt sometext_txt.cpp
 
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif

int main(int argc, char **argv);

int useconst = 0;
int zeroterminated = 0;
 
int myfgetc(FILE *f)
{
  int c = fgetc(f);
  if (c == EOF && zeroterminated) {
    zeroterminated = 0;
    return 0;
  }
  return c;
}
 
 
char* str2upr(char *s)
{
  char * r = (char *) calloc(strlen(s)+1, sizeof(char));
  
  int i = 0;
  while(*s)
    {
      r[i] = toupper(*s);
      ++i;
      ++s;
    }
  return r;
} 
 
 
 
void process(const char *ifname, const char *ofname)
{
  FILE *ifile, *ofile;
  ifile = fopen(ifname, "rb");
  if (ifile == NULL) {
    fprintf(stderr, "cannot open %s for reading\n", ifname);
    exit(1);
  }
  ofile = fopen(ofname, "wb");
  if (ofile == NULL) {
    fprintf(stderr, "cannot open %s for writing\n", ofname);
    exit(1);
  }
  char buf[PATH_MAX], *p;
  const char *cp;
  if ((cp = strrchr(ifname, '/')) != NULL)
    ++cp;
  else {
    if ((cp = strrchr(ifname, '\\')) != NULL)
      ++cp;
    else
      cp = ifname;
  }
  strcpy(buf, cp);
  for (p = buf; *p != '\0'; ++p)
    if (!isalnum(*p))
      *p = '_';
  fprintf(ofile, "#ifndef %s_H\n#define %s_H\nstatic %sunsigned char %s[] = {\n",
         str2upr(buf), str2upr(buf), useconst ? "const " : "", buf);
  int c, col = 1;
  while ((c = myfgetc(ifile)) != EOF) {
    if (col >= 78 - 6) {
      fputc('\n', ofile);
      col = 1;
    }
    fprintf(ofile, "0x%.2x, ", c);
    col += 6;
 
  }
  fprintf(ofile, "\n};\n#endif\n");
 
  fclose(ifile);
  fclose(ofile);
}
 
void usage(void)
{
  fprintf(stderr, "usage: bin2c [-cz] <input_file> <output_file>\n");
  exit(1);
}
 
int main(int argc, char **argv)
{
  while (argc > 3) {
    if (!strcmp(argv[1], "-c")) {
      useconst = 1;
      --argc;
      ++argv;
    } else if (!strcmp(argv[1], "-z")) {
      zeroterminated = 1;
      --argc;
      ++argv;
    } else {
      usage();
    }
  }
  if (argc != 3) {
    usage();
  }
  process(argv[1], argv[2]);
  return 0;
}
You're awesome! Thank you so much, that is exactly what I needed. Thanks for posting that source.

bin2c files.tgz files.tgz.h


files.tgz.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef FILES_TGZ_H
#define FILES_TGZ_H
static unsigned char files_tgz[] = {
0x1f, 0x8b, 0x08, 0x00, 0xca, 0x38, 0xd2, 0x4e, 0x00, 0x03, 0xed, 0xce, 
0xb1, 0x0d, 0xc2, 0x30, 0x00, 0x04, 0x40, 0x8f, 0xe2, 0x09, 0x22, 0x3b, 
0x71, 0x9c, 0x79, 0x2c, 0xa5, 0xa2, 0x00, 0x29, 0x18, 0x89, 0xf1, 0x09, 
0x45, 0x24, 0x1a, 0x44, 0x15, 0xaa, 0xbb, 0xe6, 0x8b, 0xff, 0xe2, 0xd7, 
0xd6, 0xdb, 0xd0, 0x9f, 0x3d, 0x9c, 0x28, 0xed, 0x6a, 0x29, 0xef, 0xcc, 
0xcb, 0x9c, 0x3e, 0xf3, 0x10, 0x72, 0xae, 0xfb, 0x64, 0x2a, 0xe3, 0xbc, 
0x84, 0x94, 0xc7, 0x54, 0x6a, 0x88, 0xe9, 0xcc, 0x53, 0x87, 0xc7, 0xbd, 
0xb7, 0x2d, 0xc6, 0x70, 0xb9, 0x6d, 0x6b, 0xbb, 0x7e, 0xdf, 0xfd, 0xea, 
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x8f, 0x5e, 
0x3c, 0xd0, 0x57, 0xc0, 0x00, 0x28, 0x00, 0x00, 
};
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <fstream>
using namespace std;

#include "files.tgz.h"

#define length(a) (sizeof( a )/sizeof( *a ))

int main()
{
    ofstream outfile("out.tgz", ofstream::binary);
    
    int stop = length(files_tgz);
    int current = 0;
    for (current; current < stop; current++)
    {
        outfile.put(f#include <fstream>
using namespace std;

#include "files.tgz.h"

#define length(a) (sizeof( a )/sizeof( *a ))

int main()
{
    ofstream outfile("out.tgz", ofstream::binary);
    
    int stop = length(files_tgz);
    int current = 0;
    for (current; current < stop; current++)
    {
        outfile.put(files_tgz[current]);
    }
    
    outfile.close();
    
    return 0;
}
iles_tgz[current]);
    }
    
    outfile.close();
    
    return 0;
}


I was also shown another way to do it here: http://ubuntuforums.org/showthread.php?p=11493250#post11493225
Last edited on
Topic archived. No new replies allowed.