6 #include "appimage/appimage.h"
7 #include "getsection.h"
9 /* Check if a file is an AppImage. Returns the image type if it is, or -1 if it isn't */
10 int appimage_get_type(const char* path
, bool verbose
)
12 FILE *f
= fopen(path
, "rt");
17 /* Check magic bytes at offset 8 */
18 fseek(f
, 8, SEEK_SET
);
19 fread(buffer
, 1, 3, f
);
21 if((buffer
[0] == 0x41) && (buffer
[1] == 0x49) && (buffer
[2] == 0x01)){
23 fprintf(stderr
, "_________________________\n");
26 fprintf(stderr
, "AppImage type 1\n");
29 } else if((buffer
[0] == 0x41) && (buffer
[1] == 0x49) && (buffer
[2] == 0x02)){
31 fprintf(stderr
, "_________________________\n");
34 fprintf(stderr
, "AppImage type 2\n");
38 if((g_str_has_suffix(path
,".AppImage")) || (g_str_has_suffix(path
,".appimage"))) {
40 fprintf(stderr
, "_________________________\n");
43 fprintf(stderr
, "Blindly assuming AppImage type 1\n");
44 fprintf(stderr
, "The author of this AppImage should embed the magic bytes, see https://github.com/AppImage/AppImageSpec\n");
49 fprintf(stderr
, "_________________________\n");
52 fprintf(stderr
, "Unrecognized file '%s'\n", path
);
61 bool appimage_type2_digest_md5(const char* path
, char* digest
) {
62 // skip digest, signature and key sections in digest calculation
63 unsigned long digest_md5_offset
= 0, digest_md5_length
= 0;
64 if (!appimage_get_elf_section_offset_and_length(path
, ".digest_md5", &digest_md5_offset
, &digest_md5_length
))
67 unsigned long signature_offset
= 0, signature_length
= 0;
68 if (!appimage_get_elf_section_offset_and_length(path
, ".sha256_sig", &signature_offset
, &signature_length
))
71 unsigned long sig_key_offset
= 0, sig_key_length
= 0;
72 if (!appimage_get_elf_section_offset_and_length(path
, ".sig_key", &sig_key_offset
, &sig_key_length
))
75 GChecksum
*checksum
= g_checksum_new(G_CHECKSUM_MD5
);
77 // read file in chunks
78 static const int chunk_size
= 4096;
80 FILE *fp
= fopen(path
, "r");
82 // determine file size
83 fseek(fp
, 0L, SEEK_END
);
84 const long file_size
= ftell(fp
);
87 long bytes_left
= file_size
;
89 // if a section spans over more than a single chunk, we need emulate null bytes in the following chunks
90 ssize_t bytes_skip_following_chunks
= 0;
92 while (bytes_left
> 0) {
93 char buffer
[chunk_size
];
95 long current_position
= ftell(fp
);
97 ssize_t bytes_left_this_chunk
= chunk_size
;
99 // first, check whether there's bytes left that need to be skipped
100 if (bytes_skip_following_chunks
> 0) {
101 ssize_t bytes_skip_this_chunk
= (bytes_skip_following_chunks
% chunk_size
== 0) ? chunk_size
: (bytes_skip_following_chunks
% chunk_size
);
102 bytes_left_this_chunk
-= bytes_skip_this_chunk
;
104 // we could just set it to 0 here, but it makes more sense to use -= for debugging
105 bytes_skip_following_chunks
-= bytes_skip_this_chunk
;
107 // make sure to skip these bytes in the file
108 fseek(fp
, bytes_skip_this_chunk
, SEEK_CUR
);
111 // check whether there's a section in this chunk that we need to skip
112 if (digest_md5_offset
!= 0 && digest_md5_length
!= 0 && digest_md5_offset
- current_position
> 0 && digest_md5_offset
- current_position
< chunk_size
) {
113 ssize_t begin_of_section
= (digest_md5_offset
- current_position
) % chunk_size
;
114 // read chunk before section
115 fread(buffer
, sizeof(char), (size_t) begin_of_section
, fp
);
117 bytes_left_this_chunk
-= begin_of_section
;
118 bytes_left_this_chunk
-= digest_md5_length
;
120 // if bytes_left is now < 0, the section exceeds the current chunk
121 // this amount of bytes needs to be skipped in the future sections
122 if (bytes_left_this_chunk
< 0) {
123 bytes_skip_following_chunks
= (size_t) (-1 * bytes_left_this_chunk
);
124 bytes_left_this_chunk
= 0;
127 // if there's bytes left to read, we need to seek the difference between chunk's end and bytes_left
128 fseek(fp
, (chunk_size
- bytes_left_this_chunk
- begin_of_section
), SEEK_CUR
);
131 // check whether there's a section in this chunk that we need to skip
132 if (signature_offset
!= 0 && signature_length
!= 0 && signature_offset
- current_position
> 0 && signature_offset
- current_position
< chunk_size
) {
133 ssize_t begin_of_section
= (signature_offset
- current_position
) % chunk_size
;
134 // read chunk before section
135 fread(buffer
, sizeof(char), (size_t) begin_of_section
, fp
);
137 bytes_left_this_chunk
-= begin_of_section
;
138 bytes_left_this_chunk
-= signature_length
;
140 // if bytes_left is now < 0, the section exceeds the current chunk
141 // this amount of bytes needs to be skipped in the future sections
142 if (bytes_left_this_chunk
< 0) {
143 bytes_skip_following_chunks
= (size_t) (-1 * bytes_left_this_chunk
);
144 bytes_left_this_chunk
= 0;
147 // if there's bytes left to read, we need to seek the difference between chunk's end and bytes_left
148 fseek(fp
, (chunk_size
- bytes_left_this_chunk
- begin_of_section
), SEEK_CUR
);
151 // check whether there's a section in this chunk that we need to skip
152 if (sig_key_offset
!= 0 && sig_key_length
!= 0 && sig_key_offset
- current_position
> 0 && sig_key_offset
- current_position
< chunk_size
) {
153 ssize_t begin_of_section
= (sig_key_offset
- current_position
) % chunk_size
;
154 // read chunk before section
155 fread(buffer
, sizeof(char), (size_t) begin_of_section
, fp
);
157 bytes_left_this_chunk
-= begin_of_section
;
158 bytes_left_this_chunk
-= sig_key_length
;
160 // if bytes_left is now < 0, the section exceeds the current chunk
161 // this amount of bytes needs to be skipped in the future sections
162 if (bytes_left_this_chunk
< 0) {
163 bytes_skip_following_chunks
= (size_t) (-1 * bytes_left_this_chunk
);
164 bytes_left_this_chunk
= 0;
167 // if there's bytes left to read, we need to seek the difference between chunk's end and bytes_left
168 fseek(fp
, (chunk_size
- bytes_left_this_chunk
- begin_of_section
), SEEK_CUR
);
171 // check whether we're done already
172 if (bytes_left_this_chunk
> 0) {
173 // read data from file into buffer with the correct offset in case bytes have to be skipped
174 fread(buffer
+ (chunk_size
- bytes_left_this_chunk
), sizeof(char), (size_t) bytes_left_this_chunk
, fp
);
177 // feed buffer into checksum calculation
178 g_checksum_update(checksum
, (const guchar
*) buffer
, chunk_size
);
180 bytes_left
-= chunk_size
;
183 gsize digest_len
= 16;
184 g_checksum_get_digest(checksum
, (guint8
*) digest
, &digest_len
);
191 char* appimage_hexlify(const char* bytes
, const size_t numBytes
) {
192 // first of all, allocate the new string
193 // a hexadecimal representation works like "every byte will be represented by two chars"
194 // additionally, we need to null-terminate the string
195 char* hexlified
= (char*) calloc((2 * numBytes
+ 1), sizeof(char));
197 for (size_t i
= 0; i
< numBytes
; i
++) {
199 sprintf(buffer
, "%02x", (unsigned char) bytes
[i
]);
200 strcat(hexlified
, buffer
);