LinuxQuestions.org
Support LQ: Use code LQ3 and save $3 on Domain Registration
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 11-18-2011, 03:14 PM   #1
Zssfssz
Member
 
Registered: Sep 2011
Location: Las Vegas!
Distribution: Ubuntu n' Flavors, ReactOS, MINIX3, FreeDOS, Arch
Posts: 339

Rep: Reputation: Disabled
Post Make a self extractor


OK, I want o make a self extractor(C++)(CLI).
I know how to use binary fstream but dont know how to put a file in the EXE or how to use it once its in. Can anyone help?
MinGW Compiler
 
Old 11-19-2011, 08:15 AM   #2
millgates
Member
 
Registered: Feb 2009
Location: 192.168.x.x
Distribution: Slackware
Posts: 651

Rep: Reputation: 269Reputation: 269Reputation: 269
A simple, straightforward way of doing that would be storing the data in a variable:
Code:
unsigned char file[FILE_SIZE] = {0x01, 0x02, 0x03, ...};
For large files, that would not be very practical. You might write a simple program to generate a file containing the data in this form for you.

Alternatively, you may try a more sophisticated aproach.

You may also find this interesting.

Last edited by millgates; 11-19-2011 at 01:56 PM.
 
Old 11-19-2011, 03:41 PM   #3
Zssfssz
Member
 
Registered: Sep 2011
Location: Las Vegas!
Distribution: Ubuntu n' Flavors, ReactOS, MINIX3, FreeDOS, Arch
Posts: 339

Original Poster
Rep: Reputation: Disabled
HOw would I write a program to do it for me? (it sounds awesome!)
 
Old 11-19-2011, 05:53 PM   #4
millgates
Member
 
Registered: Feb 2009
Location: 192.168.x.x
Distribution: Slackware
Posts: 651

Rep: Reputation: 269Reputation: 269Reputation: 269
Quote:
Originally Posted by Zssfssz View Post
HOw would I write a program to do it for me? (it sounds awesome!)
well, you could probably use od and sed (I found this somewhere)
Code:
(echo "const unsigned char binary_data[] = {"; od -txC -v myfile.bin | sed -e "s/^[0-9]*//" -e s"/ \([0-9a-f][0-9a-f]\)/0x\1,/g" -e"\$d" | sed -e"\$s/,$/};/")
in C, on the other hand, it could look like this (yes, I just love doing everything in C/C++ while there are better tools to do it)

Code:
#include <stdio.h>

int main(int argc, char *argv[]) {
	FILE *fpin, *fpout;
	int counter = 0;
	int c;
	if (argc != 3) {
	        fprintf(stderr, "usage: %s [INPUT FILE] [OUTPUT FILE]", argv[0]);
	        return 1;
       	}

	fpin = fopen(argv[1], "rb");
	if ( ! fpin ) {
		fprintf(stderr, "err: could not open file \"%s\" for reading", argv[1]);
		return 2;
	}

	fpout = fopen(argv[2], "w");
	if ( ! fpout ) {
		fprintf(stderr, "err: could not open file \"%s\" for writing", argv[2]);
		fclose(fpin);
		return 2;
	}

	fprintf(fpout, "const unsigned char data[] = {\n");
	while ( fread(&c, 1, 1, fpin) ) {
		if (counter == 10) { counter = 0; fprintf(fpout, ",\n"); }
		fprintf(fpout, counter++ == 0 ? "\t0x%02x" : ", 0x%02x", c);
	}
	fprintf(fpout, "\n};");
	fclose(fpin);
	fclose(fpout);
	return 0;
}
Could use some improvement, though, such as using a buffer to store the input.

There are probably as many ways of doing this as there are programming languages. You can also try exporting the file as C source from a hex editor or something.
 
Old 11-19-2011, 06:05 PM   #5
Zssfssz
Member
 
Registered: Sep 2011
Location: Las Vegas!
Distribution: Ubuntu n' Flavors, ReactOS, MINIX3, FreeDOS, Arch
Posts: 339

Original Poster
Rep: Reputation: Disabled
I tried that with a rather large file and the output was only 3 bytes (Supposed to be 501 kilos) (the text hexadecimal output thing was fine the actual binary file wasn't)
I know (took a half hour for the precompiler to get done) but any help?

Last edited by Zssfssz; 11-19-2011 at 08:23 PM.
 
Old 11-19-2011, 09:08 PM   #6
SigTerm
Member
 
Registered: Dec 2009
Distribution: Slackware 12.2
Posts: 379

Rep: Reputation: 233Reputation: 233Reputation: 233
Quote:
Originally Posted by Zssfssz View Post
OK, I want o make a self extractor(C++)(CLI).
I know how to use binary fstream but dont know how to put a file in the EXE or how to use it once its in. Can anyone help?
MinGW Compiler
Append file at the end of exe. When program starts, let it read its own header in order to determine actual size of executable code, then open its own executable file, skip number of executable bytes, and read the data. Or store size of exe somewhere within program code as a constant, and patch it with correct value once program has been compiled.

Quote:
Originally Posted by millgates View Post
For large files, that would not be very practical.
For a larger files some compilers may be unable to process the array.
 
Old 11-19-2011, 09:25 PM   #7
Zssfssz
Member
 
Registered: Sep 2011
Location: Las Vegas!
Distribution: Ubuntu n' Flavors, ReactOS, MINIX3, FreeDOS, Arch
Posts: 339

Original Poster
Rep: Reputation: Disabled
Um... Mr.SigTerm I AM NOT DENNIS RITCHIE!!!!! Could you please explain that more clearly? I have no idea how to do almost any of that!
How do I append the file!?!? How do I get the executable's size!?!? ECT!?!?
 
Old 11-19-2011, 09:51 PM   #8
SigTerm
Member
 
Registered: Dec 2009
Distribution: Slackware 12.2
Posts: 379

Rep: Reputation: 233Reputation: 233Reputation: 233
7zip is an opensource archiver and it has self-extractor module. You could try to see how it works - source code should be available.

Quote:
Originally Posted by Zssfssz View Post
How do I append the file!?!?
You compile self-extractor that contains NO data to be extracted, then open (fopen("program.exe", "wba")) it with external program, seek to the end of file, and write data you want module to unpack into file using fwrite. For that windows platform has "copy /b" shell command and linux has "cat".

When resulting exe launches, it should skip to the beginning of data, and read from it. To do that you need to find file that corresponds to current module and read from it (GetModuleFilename on windows platform), or get a pointer to module as it is loaded into memory (in some versions of windows you could cast GetModuleHandle() result into pointer, but I'm not sure if this is even documented functionality).

The trick is to determine offset of data.
You can try to do that by:
  1. making self-extractor parse its own header (IMAGE_FILE_HEADER on msdn), calculate size of exe, and skip required number of bytes. This is not guaranteed to work, and might be complicated.
  2. (easiest) You could store size of program file within program in global constant variable (static const long programSize = 0 and update this variable after program has been compiled, by opening file, locating required offset and writing new value into it. This is the easiest method. The trick is to locate the variable once program has been compiled. To do so, you could either plase a "marker" around it, or use disassembler to locate it. There might be a better way to do it. If your compiler produces exe of same size during every compilation, then you simply could compile program twice - first time to determine resulting program size, and next time - with correctly set constant value. The problem with this approach is that somebody tries to run "gnu strip" on your program, it most likely will break everything.

Last edited by SigTerm; 11-19-2011 at 09:54 PM.
 
Old 11-20-2011, 12:27 AM   #9
Zssfssz
Member
 
Registered: Sep 2011
Location: Las Vegas!
Distribution: Ubuntu n' Flavors, ReactOS, MINIX3, FreeDOS, Arch
Posts: 339

Original Poster
Rep: Reputation: Disabled
I have looked at 7zip but I can't find the command line version of it and I just got to diologs In GUI programing. So how would I use the size of the program to determine what to extract? How would I make the program write this data? Is there a easy way to get my IDE (Code::Blocks) to do this for me (as in add file to executable)? Am I hopeless? I loved the first hexadecimal thing (could you give me an outline of what it is doing? I want to port it to C++) but the file I want to try it on is ~500 Kilobytes.
 
Old 11-20-2011, 02:46 AM   #10
firstfire
Member
 
Registered: Mar 2006
Location: Ekaterinburg, Russia
Distribution: Debian, Ubuntu
Posts: 636

Rep: Reputation: 372Reputation: 372Reputation: 372Reputation: 372
Hi.

Suppose you want to incorporate string "123" (3 bytes length) to the executable file "a.out". For simplicity I assume that "a.out", when run, just prints to stdout its payload (that is the string 123).

It is not a problem to append "123" to a.out. For example, on linux:

Code:
echo -n "123" >> a.out
(`-n' suppress trailing newline)

Your program should first open its own binary, then seek to 3 bytes back from its end and print contents of the file to the end. To do that your program have to know that its payload is 3 bytes length. This may be specified at compile time.

Here is an example.
Code:
// file self-extract.c

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#ifndef N
	#define N 0
#endif

int main(int argc, char* argv[])
{
	int fd = open(argv[0], O_RDONLY);

	if (fd == -1)
	{
		perror("Can't open file\n");
		return 1;
	}

	if (lseek(fd, -N, SEEK_END) == -1)
	{
		perror("Can't seek\n");
		return 1;
	}

	char buf;
	while ( read(fd, &buf, 1) )
	{
		putchar(buf);
	}
	return 0;
}
Usage is as follows:
Code:
$ gcc -D N=3  self-extract.c
$ echo -n "123" >> ./a.out
$ ./a.out
123$
$-sign in th last line is a shell prompt.

Of course your program can do more complicated things with payload than just printing it. The code may require some modification to compile on Windows.

Hope this helps.

PS. If you don't know how to append to the file, follow SigTerm's suggestion -- use `copy' utility or write your own.

Last edited by firstfire; 11-20-2011 at 12:29 PM.
 
Old 11-21-2011, 03:17 PM   #11
Zssfssz
Member
 
Registered: Sep 2011
Location: Las Vegas!
Distribution: Ubuntu n' Flavors, ReactOS, MINIX3, FreeDOS, Arch
Posts: 339

Original Poster
Rep: Reputation: Disabled
How would I seek throughthe file? Would this be easyer in Perl? I know perl but i thought scripted languiges had a weekness in storing binary files in them. (if the file was outside of that then it would be easy.)
I also know minute ammounts of python and ruby (weekest being ruby) but ruby wont start on my computer...
So, how do i seek through the file, and would this be easyer in Perl?

I love Perl......
 
Old 11-21-2011, 11:14 PM   #12
firstfire
Member
 
Registered: Mar 2006
Location: Ekaterinburg, Russia
Distribution: Debian, Ubuntu
Posts: 636

Rep: Reputation: 372Reputation: 372Reputation: 372Reputation: 372
Hi.

The situation is different for compiled languages (like C) and for interpreted languages (like Perl).

1. In C you write your program in a text file, say `prog.c', then you compile it to binary file, on linux just `prog', and then run it: `./prog' on linux. Executable file is different from program source. In this situation your program (self-extractor) should open its own binary file and locate the payload inside. You need some kind of `seek' function for this. And in C you already have one, it is called `lseek' (in linux you can run `man 2 lseek' for details or see here and this example). In my previous post I use lseek to go to specified number of bytes back from the end of file.

2. There are no such thing as executable (binary) file for interpreted languages. So you don't need to load it and then find something there. Instead you just put the information you want straight to the script, for example using here document and do what you want with it. This approach is very similar to putting the data to C-array (see first post), but much simpler and standard for such languages. In fact, some time ago this approach was used to make self-extracting shell archives (shar) -- see here and here.
Example in perl:
Code:
print << 'END'
Your
data
goes
here
END
Note that here-documents are designed to work with textual data only so binary data will require some preprocessing (like encoding to base64 or to hex format).

Note also that you will need an interpreter (correctly installed perl executable in your case) in order to extract your data automatically.

Hope this helps.

Last edited by firstfire; 11-21-2011 at 11:16 PM. Reason: fix a typo
 
Old 11-22-2011, 12:03 AM   #13
Zssfssz
Member
 
Registered: Sep 2011
Location: Las Vegas!
Distribution: Ubuntu n' Flavors, ReactOS, MINIX3, FreeDOS, Arch
Posts: 339

Original Poster
Rep: Reputation: Disabled
This pice of info might also chage some things:
The file is a non OS/2\Windows specific DLL. I wrote it and have the endure source (der).
Would it be possible to place the code inside of a variable or something and when it's comPiled it gets turned into binary data.
I acctualy have both strawberrie and ActiveState perl on my computer (the Linux side doesnt have one because I dont have Internet nor the time to to download all dependicys). Still deciding which one get in the regishtry and path... They both have ups n downs.

Thanks!
 
  


Reply

Tags
c++, cli


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Question on CD Image extractor bbmak Linux - Software 1 10-25-2004 09:17 PM
I need an .IT file extractor MacNews Linux - Software 4 09-13-2003 04:22 PM
Alba Extractor DigitalTygrrr Linux - Software 3 07-28-2003 01:22 AM
Album Wrap Extractor ? DigitalTygrrr Linux - Software 4 07-20-2003 07:22 PM
zip viewer/extractor ixion Linux - Software 3 01-18-2003 10:29 PM


All times are GMT -5. The time now is 03:41 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration