-
Notifications
You must be signed in to change notification settings - Fork 0
/
quickbms.c
1480 lines (1331 loc) · 56.9 KB
/
quickbms.c
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
Copyright 2009-2017 Luigi Auriemma
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
http://www.gnu.org/licenses/gpl-2.0.txt
*/
#define _WIN32_WINNT 0x0601
#define _WIN32_WINDOWS 0x0601
#define WINVER 0x0601
//#define NOLFS
#ifndef NOLFS // 64 bit file support not really needed since the tool uses signed 32 bits at the moment, anyway I leave it enabled
#define _LARGE_FILES // if it's not supported the tool will work
#define __USE_LARGEFILE64 // without support for large files
#define __USE_FILE_OFFSET64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <sys/stat.h>
#include <errno.h>
#include <time.h>
#include <stdarg.h>
#include <math.h>
#include <inttypes.h>
#include <locale.h>
#include <fcntl.h>
#include "stristr.c"
#include "extra/xalloc.h"
#include "extra/uthash_real_alloc.h"
#include "extra/utlist.h"
// this is the old method used by quickbms to handle short strings.
// currently it has been disabled and will rely entirely on allocated memory instead of static buffers.
// I'm still testing the effects on the performances, QUICKBMS_VAR_STATIC is stable and has ever worked,
// while the other method is slower (frostbite.bms is sloooooow) but doesn't use work-arounds.
// so... do NOT touch it!
#define QUICKBMS_VAR_STATIC
// disabled by default because there are some things that don't convince me
// for example during the disassembling of shellcode_Alpha2.txt
#ifdef ENABLE_BEAENGINE
#define BEA_ENGINE_STATIC
#define BEA_USE_STDCALL
#include <BeaEngine.h>
#endif
//typedef int8_t i8;
typedef uint8_t u8;
//typedef int16_t i16;
typedef uint16_t u16;
typedef int32_t i32;
typedef uint32_t u32;
//typedef int64_t i64;
typedef uint64_t u64;
typedef int8_t int8;
typedef uint8_t uint8;
typedef int16_t int16;
typedef uint16_t uint16;
typedef int32_t int32;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
typedef unsigned char byte; // for sflcomp
typedef unsigned short word; // for sflcomp
#define QUICKBMS
// in case you want to make QuickBMS 64bit compatible
// start
#ifdef QUICKBMS64
#define INTSZ 64
#define QUICKBMS_int int64_t // trick for forcing the usage of signed 32 bit numbers on any system without modifying the code
#define QUICKBMS_u_int uint64_t // used only in some rare occasions
#define PRId PRId64
#define PRIu PRIu64
#define PRIx "016"PRIx64
#else
#define INTSZ 32
#define QUICKBMS_int int32_t // trick for forcing the usage of signed 32 bit numbers on any system without modifying the code
#define QUICKBMS_u_int uint32_t // used only in some rare occasions
#define PRId PRId32
#define PRIu PRIu32
#define PRIx "08"PRIx32
#endif
// end
#define PATH_DELIMITERS "\\/"
#ifdef WIN32
#else
#define stricmp strcasecmp
#define strnicmp strncasecmp
//#define stristr strcasestr
typedef uint32_t DWORD;
#endif
int (*real_strcmp) ( const char * str1, const char * str2 ) = strcmp;
int (*real_stricmp) ( const char * str1, const char * str2 ) = stricmp;
int (*real_strncmp) ( const char * str1, const char * str2, size_t num ) = strncmp;
int (*real_strnicmp) ( const char * str1, const char * str2, size_t num ) = strnicmp;
i32 mystrcmp(const char *a, const char *b);
i32 mystricmp(const char *a, const char *b);
i32 mystrncmp(const char *a, const char *b, i32 n);
i32 mystrnicmp(const char *a, const char *b, i32 n);
#define strcmp mystrcmp
#undef stricmp
#define stricmp mystricmp
#define strncmp mystrncmp
#undef strnicmp
#define strnicmp mystrnicmp
// yeah it's cdecl by default
int /*__cdecl*/ fake_printf(const char *__format, ...) {
return 0;
}
int /*__cdecl*/ (*backup_real_printf) (const char *__format, ...) = printf;
int /*__cdecl*/ (*real_printf) (const char *__format, ...) = printf;
int /*__cdecl*/ fake_fprintf(FILE *__stream, const char *__format, ...) {
if((__stream == stdout) || (__stream == stderr)) return 0;
register int __retval;
__builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
__retval = /*__mingw_*/vfprintf( __stream, __format, __local_argv );
__builtin_va_end( __local_argv );
return __retval;
}
int /*__cdecl*/ (*backup_real_fprintf) (FILE *__stream, const char *__format, ...) = fprintf;
int /*__cdecl*/ (*real_fprintf) (FILE *__stream, const char *__format, ...) = fprintf;
#define printf real_printf
#define fprintf real_fprintf
#include "quickiso.c"
#include "quickzip.c"
#include <zlib.h>
#include <bzlib.h>
#ifndef DISABLE_UCL // add -DDISABLE_UCL at compiling if you don't have UCL
#include <ucl/ucl.h>
#endif
#ifndef DISABLE_LZO // add -DDISABLE_LZO at compiling if you don't have LZO
#include <lzo/lzo1.h>
#include <lzo/lzo1a.h>
#include <lzo/lzo1b.h>
#include <lzo/lzo1c.h>
#include <lzo/lzo1f.h>
#include <lzo/lzo1x.h>
#include <lzo/lzo1y.h>
#include <lzo/lzo1z.h>
#include <lzo/lzo2a.h>
#else
#include "libs/minilzo/minilzo.h"
#endif
#include "compression/blast.h"
#include "compression/sflcomp.h"
#include "libs/lzma/LzmaDec.h"
#include "libs/lzma/Lzma2Dec.h"
#include "libs/lzma/Bra.h"
#include "libs/lzma/LzmaEnc.h"
#include "libs/lzma/Lzma2Enc.h"
// or use -DDISABLE_SSL
#ifndef DISABLE_SSL
// it's useless to enable the following
//#define OPENSSL_DOING_MAKEDEPEND
//#define OPENSSL_NO_KRB5
#include <openssl/ossl_typ.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/blowfish.h>
#include <openssl/hmac.h>
#endif
#include "encryption/tea.h"
#include "encryption/xtea.h"
#include "encryption/xxtea.h"
#include "myenc.c"
#include "encryption/twofish.h"
#include "encryption/seed.h"
#include "encryption/serpent.h"
#include "encryption/ice.h"
#include "encryption/rotor.c"
//#include "encryption/libkirk/kirk_engine.h"
#include "encryption/sph.h"
int kirk_CMD0(u8* outbuff, u8* inbuff, int size, int generate_trash);
int kirk_CMD1(u8* outbuff, u8* inbuff, int size, int do_check);
int kirk_CMD4(u8* outbuff, u8* inbuff, int size);
int kirk_CMD7(u8* outbuff, u8* inbuff, int size);
int kirk_CMD10(u8* inbuff, int insize);
int kirk_CMD11(u8* outbuff, u8* inbuff, int size);
int kirk_CMD14(u8* outbuff, int size);
int kirk_init(); //CMD 0xF?
void xtea_crypt_ecb( xtea_context *ctx, int mode, u8 input[8], u8 output[8] );
#ifndef DISABLE_MCRYPT
#include <mcrypt.h>
#endif
//#define DISABLE_TOMCRYPT // useless at the moment
#ifndef DISABLE_TOMCRYPT
#define USE_LTM
#define LTC_MECC
#define LTM_DESC
#define LTC_SOURCE
#define LTC_MRSA
#define LTC_MKAT
#define LTC_MDH
#define LTC_MDSA
#define LTC_DER
#include <tomcrypt.h>
#endif
void zipcrypto_init_keys(const char* passwd,uint32_t* pkeys,const uint32_t* pcrc_32_tab);
void zipcrypto_decrypt(uint32_t* pkeys,const uint32_t* pcrc_32_tab, unsigned char *data, int datalen);
void zipcrypto_encrypt(uint32_t* pkeys,const uint32_t* pcrc_32_tab, unsigned char *data, int datalen);
int threeway_setkey(unsigned *key, unsigned char *data, int datalen);
void threeway_encrypt(unsigned *key, unsigned char *data, int datalen);
void threeway_decrypt(unsigned *key, unsigned char *data, int datalen);
void skipjack_makeKey(byte key[10], byte tab[10][256]);
void skipjack_encrypt(byte tab[10][256], byte in[8], byte out[8]);
void skipjack_decrypt(byte tab[10][256], byte in[8], byte out[8]);
#include "encryption/anubis.h"
typedef struct { Byte rk[16*17]; int Nr; } aria_ctx_t;
int ARIA_DecKeySetup(const Byte *mk, Byte *rk, int keyBits);
int ARIA_EncKeySetup(const Byte *mk, Byte *rk, int keyBits);
void ARIA_Crypt(const Byte *i, int Nr, const Byte *rk, Byte *o);
u_int *crypton_set_key(const u_int in_key[], const u_int key_len, u_int l_key[104]);
u_int crypton_encrypt(const u_int in_blk[4], u_int out_blk[4], u_int l_key[104]);
u_int crypton_decrypt(const u_int in_blk[4], u_int out_blk[4], u_int l_key[104]);
u_int *frog_set_key(const u_int in_key[], const u_int key_len);
void frog_encrypt(const u_int in_blk[4], u_int out_blk[4]);
void frog_decrypt(const u_int in_blk[4], u_int out_blk[4]);
typedef struct { u_int iv[2]; u_int key[8]; int type; } gost_ctx_t;
void gost_kboxinit(void);
void gostcrypt(u_int const in[2], u_int out[2], u_int const key[8]);
void gostdecrypt(u_int const in[2], u_int out[2], u_int const key[8]);
void gostofb(u_int const *in, u_int *out, int len, u_int const iv[2], u_int const key[8]);
void gostcfbencrypt(u_int const *in, u_int *out, int len, u_int iv[2], u_int const key[8]);
void gostcfbdecrypt(u_int const *in, u_int *out, int len, u_int iv[2], u_int const key[8]);
void lucifer(unsigned char *);
void lucifer_loadkey(unsigned char *, int);
u_int *mars_set_key(u_int key_blk[], u_int key_len);
void mars_encrypt(u_int in_blk[], u_int out_blk[]);
void mars_decrypt(u_int in_blk[], u_int out_blk[]);
void misty1_keyinit(u_int *ek, u_int *k);
void misty1_decrypt_block(u_int *ek,u_int c[2], u_int p[2]);
void misty1_encrypt_block(u_int *ek, u_int p[2], u_int c[2]);
typedef struct { u_int k[4]; } NOEKEONstruct;
void NOEKEONkeysetup(const unsigned char * const key,
NOEKEONstruct * const structpointer);
void NOEKEONencrypt(const NOEKEONstruct * const structpointer,
const unsigned char * const plaintext,
unsigned char * const ciphertext);
void NOEKEONdecrypt(const NOEKEONstruct * const structpointer,
const unsigned char * const ciphertext,
unsigned char * const plaintext);
#include "encryption/seal.h"
#include "encryption/safer.h"
int pc1_128(unsigned char *cle, unsigned char *data, int size, int decenc);
int pc1_256(unsigned char *cle, unsigned char *data, int size, int decenc);
uint32_t *rc6_set_key(uint32_t *l_key, const uint32_t in_key[], const uint32_t key_len);
void rc6_encrypt(uint32_t *l_key, const uint32_t in_blk[4], uint32_t out_blk[4]);
void rc6_decrypt(uint32_t *l_key, const uint32_t in_blk[4], uint32_t out_blk[4]);
#include "encryption/isaac.h"
void isaacx_crypt(unsigned char *key, int keylen, unsigned char *data, int datasz, int do_encrypt);
void hsel_crypt(unsigned char *key, unsigned char *data, int size, int do_encrypt, char *options);
#ifdef __DJGPP__
#define NOLFS
char **__crt0_glob_function (char *arg) { return 0; }
void __crt0_load_environment_file (char *progname) { }
#endif
#define DISABLE_BACKTRACE // it makes the executable bigger and breaks compatibility with Win98 (_fstat64)
#ifdef WIN32
#include <windows.h>
//#include <psapi.h>
//#include <shlobj.h>
//#include <tlhelp32.h>
#include <wincrypt.h>
#include <direct.h>
//#include <ddk/ntifs.h> // I want compatibility even with Win9x
#include "extra/MemoryModule.h"
#ifndef DISABLE_BACKTRACE
#include "extra/backtrace.c"
#endif
#define PATHSLASH '\\'
#define LOADDLL(X) LoadLibrary(X)
#define GETFUNC(X) (void *)GetProcAddress(hlib, X)
#define CLOSEDLL FreeLibrary(hlib)
char *get_file(char *title, i32 bms, i32 multi);
char *get_folder(char *title);
#else
#include <unistd.h>
#include <dirent.h>
#include <dlfcn.h> // -ldl
#include <sys/mman.h>
#include <netinet/in.h>
#define LOADDLL(X) dlopen(X, RTLD_LAZY)
#define GETFUNC(X) (void *)dlsym(hlib, X)
#define CLOSEDLL dlclose(hlib)
#define HMODULE void *
#define GetCurrentProcessId getpid
#define PATHSLASH '/'
#ifdef __APPLE__
// don't use iconv
#else
#define USE_LIBICONV // -liconv
#endif
#endif
#if defined(_LARGE_FILES)
#if defined(__APPLE__)
#define fseek fseeko
#define ftell ftello
#elif defined(__FreeBSD__)
#elif !defined(NOLFS) // use -DNOLFS if this tool can't be compiled on your OS!
#define off_t off64_t
#define fopen fopen64
#define fseek fseeko64
#define ftell ftello64
#ifndef fstat
#ifdef WIN32
#define fstat _fstati64
#define stat _stati64
#else
#define fstat fstat64
#define stat stat64
#endif
#endif
#endif
#endif
# ifndef __cdecl
# define __cdecl __attribute__ ((__cdecl__))
# endif
# ifndef __stdcall
# define __stdcall __attribute__ ((__stdcall__))
# endif
void __cxa_pure_virtual() { while(1); }
#include "threads.h"
static u8 VER[64] = ""; // kept for compatibility with some functions
#define BUFFSZ 8192
#define MAX_IFS 16 // fixed but exagerated
#define MAX_ARGS 32 // fixed but exagerated
#define MAX_VARS 1024 // fixed but exagerated (name/value_static gives problems with allocated variables)
#define MAX_FILES 1024 // fixed but exagerated
#define MAX_CMDS 4096 // fixed but exagerated
#define MAX_ARRAYS 1024 // fixed but exagerated
#define STRINGSZ 273 // more than MAX_PATH, aligned with +1, 273*15+1 = 4096
#define VAR_VALUE_DELIMITERS 3 // unicode and so on, originally it was just 1
#define NUMBERSZ 24 // ready for 64 bits, includes also space for the NULL delimiter
#define PATHSZ 1024 // 257 was enough, theoretically the system could support 32kb but 1024 is really a lot
#define MULTI_PATHSZ 32768 // 32k limit ansi, no limit unicode
#define ENABLE_DIRECT_COPY
#ifdef QUICKBMS_VAR_STATIC
#define VAR_NAMESZ STRINGSZ // 31 // +1 for alignment, 31 for a variable name is perfect
#define VAR_VALUESZ STRINGSZ // more than 256 and big enough to contain filenames
#if VAR_NAMESZ < NUMBERSZ
ERROR VAR_NAMESZ < NUMBERSZ
#endif
#endif
#define MYLITTLE_ENDIAN 0
#define MYBIG_ENDIAN 1
#define int QUICKBMS_int
#define u_int QUICKBMS_u_int
#define QUICKBMS_DUMMY "QUICKBMS_DUMMY_TEMP"
#define CMD g_command[cmd]
#define ARG argument
#define NUM(X) CMD.num[X]
#define STR(X) CMD.str[X]
#define VARISNUM(X) var_is_a_number(CMD.var[X]) //g_variable[CMD.var[X]].isnum
#define VARNAME(X) get_varname(CMD.var[X])
#define VAR(X) get_var(CMD.var[X])
#define VAR32(X) get_var32(CMD.var[X])
#ifdef QUICKBMS_VAR_STATIC
#define VARSZ(X) g_variable[CMD.var[X]].size // due to the memory enhancement done on this tool, VARSZ returns ever STRINGSZ for sizes lower than this value... so do NOT trust this value!
#else
#define VARSZ(X) get_var_fullsz(CMD.var[X]) // causes LOT of problems with static variables, check what happened with quickbms 0.7.2a
#endif
//#define FILEZ(X) ((NUM(X) < 0) ? NULL : g_filenumber[NUM(X)].fd) // automatic support for MEMORY_FILE
#define DIRECT_ADDVAR(X,Y,Z) \
g_variable[CMD.var[X]].value = Y; \
g_variable[CMD.var[X]].value32 = 0; \
g_variable[CMD.var[X]].isnum = 0; \
g_variable[CMD.var[X]].size = Z;
#define FILEZ(X) NUM(X)
#define MEMORY_FNAME "MEMORY_FILE"
#define MEMORY_FNAMESZ (sizeof(MEMORY_FNAME) - 1)
#define TEMPORARY_FILE "TEMPORARY_FILE"
#define ALLOC_ERR alloc_err(__FILE__, __LINE__, __FUNCTION__)
#define STD_ERR(ERR) std_err(__FILE__, __LINE__, __FUNCTION__, ERR)
static void FCLOSEX(FILE *X) { if(X && (X != stdout) && (X != stderr) && (X != stdin)) fclose(X); }
#define FCLOSE(X) { FCLOSEX(X); X = NULL; } // NULL is very important!
// use FREE instead of free
#define FREE(X) if(X) { \
free(X); \
X = NULL; \
}
#define FREEX(X,Y) if(X) { \
Y; \
FREE(X) \
}
// the first 2 checks on fdnum are not necessary
#define CHECK_FILENUM if( \
(fdnum < 0) || \
(fdnum > MAX_FILES) || \
( \
!g_filenumber[fdnum].fd && \
!g_filenumber[fdnum].sd && \
!g_filenumber[fdnum].pd && \
!g_filenumber[fdnum].ad && \
!g_filenumber[fdnum].vd && \
!g_filenumber[fdnum].md \
) \
) { \
fprintf(stderr, "\nError: the specified file number (%d) has not been opened yet (line %d)\n", (i32)fdnum, (i32)__LINE__); \
myexit(QUICKBMS_ERROR_BMS); \
}
#define myatoi(X) readbase(X, 10, NULL)
#define CSTRING(X,Y) { \
mystrdup(&CMD.str[X], Y); \
CMD.num[X] = cstring(CMD.str[X], CMD.str[X], -1, NULL); \
}
#define QUICK_GETi32(X,Y) ((X[Y]) | (X[Y+1] << 8) | (X[Y+2] << 16) | (X[Y+3] << 24))
#define QUICK_GETb32(X,Y) ((X[Y+3]) | (X[Y+2] << 8) | (X[Y+1] << 16) | (X[Y] << 24))
#define QUICK_GETi16(X,Y) ((X[Y]) | (X[Y+1] << 8))
#define QUICK_GETb16(X,Y) ((X[Y+1]) | (X[Y] << 8))
#define SCAN_INPUT_FILE_PATH(OUT_BUFF, IN_NAME) \
switch(i) { \
case 0: mypath = g_bms_folder; break; \
case 1: mypath = g_exe_folder; break; \
case 2: mypath = g_file_folder; break; \
case 3: mypath = g_current_folder; break; \
case 4: mypath = g_output_folder; break; \
case 5: mypath = "."; break; \
default: mypath = NULL; break; \
} \
if(!mypath) break; \
spr(&OUT_BUFF, "%s%c%s", mypath, PATHSLASH, IN_NAME);
// numbers_to_bytes returns a static buffer so do NOT free it
// NUMS2BYTES(input, input_size, output, output_size)
#define NUMS2BYTES(A,B,C,D,E) { \
tmp = numbers_to_bytes(A, &B, 0, E); \
myalloc(&C, B, &D); \
memcpy(C, tmp, B); \
}
#define NUMS2BYTES_HEX(A,B,C,D,E) { \
tmp = numbers_to_bytes(A, &B, 1, E); \
myalloc(&C, B, &D); \
memcpy(C, tmp, B); \
}
#define MULTISTATIC 256 // this number is simply the amount of static buffers to use so that
// we can use the same function MULTISTATIC times without overlapped results!
#define strdup_dontuse "Error: do NOT use strdup, use re_strdup or mystrdup!"
#define strdup strdup_dontuse
#define far
//#define PRINTF64(X) (i32)(((X) >> 32) & 0xffffffff), (i32)((X) & 0xffffffff)
#include "defs.h"
u8 *myitoa(QUICKBMS_int num);
files_t *add_files(u8 *fname, QUICKBMS_int fsize, QUICKBMS_int *ret_files);
int debug_privileges(void);
int verbose_options(u8 *arg);
u8 *mystrdup_simple(u8 *str);
u8 *mystrdup(u8 **old_buff, u8 *str);
u8 *show_dump(int left, u8 *data, int len, FILE *stream);
int get_parameter_numbers_int(u8 *str, ...);
int get_parameter_numbers_i32(u8 *str, ...);
QUICKBMS_int readbase(u8 *data, QUICKBMS_int size, QUICKBMS_int *readn);
void g_mex_default_init(int file_only);
int start_bms(int startcmd, int nop, int this_is_a_cycle, int *invoked_if, int *invoked_break, int *invoked_continue, u8 **invoked_label);
int check_wildcard(u8 *fname, u8 *wildcard);
int check_wildcards(u8 *fname, u8 **list);
u8 *create_dir(u8 *fname, int mdir, int cdir, int is_path, int filter_bad);
int check_overwrite(u8 *fname, int check_if_present_only);
u8 *myalloc(u8 **data, QUICKBMS_int wantsize, QUICKBMS_int *currsize);
void std_err(const char *fname, i32 line, const char *func, signed char error);
void winerr(DWORD error, char *msg);
void myexit(int ret);
// boring 64bit compatibility
#undef int
#undef u_int
#if QUICKBMS_int != 32
u8 *myalloc32(u8 **data, int wantsize, int *currsize) {
QUICKBMS_int lame;
if(!currsize) {
myalloc(data, wantsize, NULL);
} else {
lame = *currsize;
myalloc(data, wantsize, &lame);
*currsize = lame;
}
return(*data);
}
#define myalloc myalloc32
#endif
#define get_parameter_numbers get_parameter_numbers_i32
// int -> 32
#include "calling_conventions.h"
#include "sign_ext.c"
#include "unz.c"
#include "extra/wcx.c"
#include "extra/window.c"
#include "extra/libtcc.h"
#include "io/sockets.c"
#include "io/process.c"
#include "io/audio.c"
#include "io/video.c"
#include "io/winmsg.c"
#undef myalloc
#define MAINPROG
#include "disasm/disasm.h"
typedef struct t_asmmodel { // Model to search for assembler command
uchar code[MAXCMDSIZE]; // Binary code
uchar mask[MAXCMDSIZE]; // Mask for binary code (0: bit ignored)
int length; // Length of code, bytes (0: empty)
int jmpsize; // Offset size if relative jump
int jmpoffset; // Offset relative to IP
int jmppos; // Position of jump offset in command
} t_asmmodel;
int Assemble(uchar *cmd,ulong ip,t_asmmodel *model,int attempt,
int constsize,uchar *errtext);
// restore int and u_int after main()
// int -> 32 or 64
#define int QUICKBMS_int
#define u_int QUICKBMS_u_int
#undef get_parameter_numbers
#define get_parameter_numbers get_parameter_numbers_int
int g_quickbms_exception_test = -1,
g_insensitive = 1;
i32 g_quickbms_argc = 0;
char **g_quickbms_argv = NULL;
char g_quickbms_arg0[PATHSZ + 1] = "";
#include "utils_unicode.c"
#include "utils.c"
#include "var.c"
#include "perform.c"
#include "hexhtml.c"
#include "file.c"
#include "cmd.c"
#include "bms.c"
#include "update.c"
#include "help.c"
int set_console_title(u8 *options_db, u8 *bms, u8 *fname) {
#ifdef WIN32
static u8 title[1024] = "";
u8 options[256 + 1];
int i,
len;
len = 0;
for(i = 0; i < 256; i++) {
if(options_db[i]) options[len++] = i;
}
options[len] = 0;
len = snprintf(
title,
sizeof(title),
"%s -%s: %s . %s",
VER,
options,
bms,
fname);
if((len < 0) || (len > sizeof(title))) {
title[sizeof(title) - 1] = 0;
}
SetConsoleTitle(title);
#endif
return 0;
}
#ifdef WIN32
// the goal of these functions is avoiding the error dialog box and terminating the process immediately
u8 *show_exception_code(int code) {
u8 *msg = NULL;
switch(code) {
case STATUS_SEGMENT_NOTIFICATION: msg = "segment notification"; break;
case STATUS_GUARD_PAGE_VIOLATION: msg = "guard page violation"; break;
case STATUS_DATATYPE_MISALIGNMENT: msg = "datatype misalignment"; break;
case STATUS_BREAKPOINT: msg = "breakpoint"; break;
case STATUS_SINGLE_STEP: msg = "single step"; break;
case STATUS_ACCESS_VIOLATION: msg = "access violation"; break;
case STATUS_IN_PAGE_ERROR: msg = "in page error"; break;
case STATUS_INVALID_HANDLE: msg = "invalid handle"; break;
case STATUS_NO_MEMORY: msg = "no memory"; break;
case STATUS_ILLEGAL_INSTRUCTION: msg = "illegal instruction"; break;
case STATUS_NONCONTINUABLE_EXCEPTION: msg = "non continuable exception"; break;
case STATUS_INVALID_DISPOSITION: msg = "invalid disposition"; break;
case STATUS_ARRAY_BOUNDS_EXCEEDED: msg = "array bounds exceeded"; break;
case STATUS_FLOAT_DENORMAL_OPERAND: msg = "float denormal operand"; break;
case STATUS_FLOAT_DIVIDE_BY_ZERO: msg = "float divide by zero"; break;
case STATUS_FLOAT_INEXACT_RESULT: msg = "float inexact result"; break;
case STATUS_FLOAT_INVALID_OPERATION: msg = "float invalid operation"; break;
case STATUS_FLOAT_OVERFLOW: msg = "float overflow"; break;
case STATUS_FLOAT_STACK_CHECK: msg = "float stack check"; break;
case STATUS_FLOAT_UNDERFLOW: msg = "float underflow"; break;
case STATUS_INTEGER_DIVIDE_BY_ZERO: msg = "divide by zero"; break;
case STATUS_INTEGER_OVERFLOW: msg = "integer overflow"; break;
case STATUS_PRIVILEGED_INSTRUCTION: msg = "privileged instruction"; break;
case STATUS_STACK_OVERFLOW: msg = "stack overflow"; break;
case STATUS_CONTROL_C_EXIT: msg = "CTRL+C exit"; break;
case STATUS_DLL_INIT_FAILED: msg = "DLL init failed"; break;
#ifdef STATUS_DLL_INIT_FAILED_LOGOFF
case STATUS_DLL_INIT_FAILED_LOGOFF: msg = "DLL init failed logoff"; break;
#endif
default: msg = ""; break;
}
return msg;
}
int show_exceptionrecord(EXCEPTION_RECORD *ExceptionRecord, i32 level) {
static void * old_addr = NULL - 1;
static int called = 0;
int i;
if(!ExceptionRecord) return -1;
if((old_addr == ExceptionRecord->ExceptionAddress) || (called >= 10)) {
// corrupted handler, it happened one time with compression 148
// yeah I know that it's not a perfect solution
TerminateProcess(GetCurrentProcess(), 9);
Sleep(-1); // it will be killed automatically
}
old_addr = ExceptionRecord->ExceptionAddress;
called++;
fprintf(stderr, "%.*s*EH* ExceptionCode %08x %s\n", level * 4, "", (i32)ExceptionRecord->ExceptionCode, show_exception_code(ExceptionRecord->ExceptionCode));
fprintf(stderr, "%.*s*EH* ExceptionFlags %08x\n", level * 4, "", (i32)ExceptionRecord->ExceptionFlags);
fprintf(stderr, "%.*s*EH* ExceptionAddress %08x\n", level * 4, "", (i32)ExceptionRecord->ExceptionAddress);
module_t *module; // placed here in case of crashes
module = scan_modules(NULL, GetCurrentProcessId(), NULL, NULL);
if(module) {
for(i = 0; module[i].addr; i++) {
if((ExceptionRecord->ExceptionAddress >= module[i].addr) && (ExceptionRecord->ExceptionAddress < (module[i].addr + module[i].size))) {
fprintf(stderr, "%.*s %p + %08x %s\n", level * 4, "", module[i].addr, (i32)(ExceptionRecord->ExceptionAddress - module[i].addr), module[i].szModule);
}
}
}
fprintf(stderr, "%.*s*EH* NumberParameters %08x\n", level * 4, "", (i32)ExceptionRecord->NumberParameters);
for(i = 0; i < ExceptionRecord->NumberParameters; i++) {
fprintf(stderr, "%.*s*EH* %08x\n", level * 4, "", (i32)ExceptionRecord->ExceptionInformation[i]);
}
show_exceptionrecord(ExceptionRecord->ExceptionRecord, level + 1);
return 0;
}
void exception_handler(EXCEPTION_POINTERS *ExceptionInfo) {
if(ExceptionInfo && ExceptionInfo->ExceptionRecord && (ExceptionInfo->ExceptionRecord->ExceptionCode <= 0x7fffffff)) {
return;
}
fprintf(stderr,
"\n"
"-------------------\n"
"*EXCEPTION HANDLER*\n"
"-------------------\n"
"An error or crash occurred:\n"
"\n"
);
if(ExceptionInfo) {
show_exceptionrecord(ExceptionInfo->ExceptionRecord, 0);
/* this hex dump is useless
u8 *p;
if(ExceptionInfo->ContextRecord) {
// alpha, mips, x86, x86_64... show_dump is easier
// skip the last zeroes to avoid too much data
for(p = (u8 *)ExceptionInfo->ContextRecord + sizeof(CONTEXT) - sizeof(u32); p >= (u8 *)ExceptionInfo->ContextRecord; p -= sizeof(u32)) {
if(((u32 *)p)[0]) break;
}
show_dump(2, (u8 *)ExceptionInfo->ContextRecord, (p + sizeof(u32)) - (u8 *)ExceptionInfo->ContextRecord /|*sizeof(CONTEXT)*|/, stderr);
}
*/
if(ExceptionInfo->ExceptionRecord && (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) && GetModuleHandle("HsSrv")) {
fprintf(stderr,
"\n"
"Probably the crash has been caused by your Asus Xonar/Unixonar drivers.\n"
"More information and details are available in quickbms.txt\n"
"Some ways to fix the bug:\n"
"- disable the GX mode (emulated EAX) of the Asus driver\n"
"- disable the Asus HookSupport Manager application (HsMgr.exe)\n"
"- start QuickBMS with the -9 option (create a link)\n"
"- contact Asus! :)\n"
"\n");
}
// backtrace part
#ifndef DISABLE_BACKTRACE
struct output_buffer ob;
output_init(&ob, g_backtrace_output, BACKTRACE_BUFFER_MAX);
if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) {
output_print(&ob,"Failed to init symbol context\n");
}
else {
bfd_init();
struct bfd_set *set = calloc(1,sizeof(*set));
_backtrace(&ob , set , 128 , ExceptionInfo->ContextRecord);
release_set(set);
SymCleanup(GetCurrentProcess());
}
fputs("\n*EH* Stack Trace:\n", stderr);
fputs(g_backtrace_output , stderr);
#endif
}
if(!g_quickbms_exception_test && XDBG_ALLOC_ACTIVE && g_is_gui) {
// the problem is caused by some programs that read the memory of the other processes
// when GetOpenFileName is called but they are so dumb to read the data before the
// allocated memory or the blocks tagged as PAGE_NOACCESS or PAGE_GUARD.
printf(
"\n"
"\n"
"It seems you have some program running on your system that doesn't allow\n"
"QuickBMS to run because it reads invalid zones of the memory of this process.\n"
"This is usually caused by Xonar drivers or some Nvidia software with special\n"
"options enabled and maybe also some antivirus software.\n"
"\n"
"You can bypass the problem by launching QuickBMS with the -9 option by\n"
"creating a link to quickbms.exe or simply by answering to the following\n"
"question:\n"
"\n"
"- Do you want to launch QuickBMS with the -9 option? (y/N)\n"
" ");
if(get_yesno(NULL) == 'y') {
// spawnv note: do not enable this (don't know why but doesn't work if you specify the folder): copycut_folder(NULL, g_quickbms_arg0);
char *myargv[g_quickbms_argc + 2 + 1]; // 2 = -9 -G
int32 i, arg, do_9=1, do_G=1;
i = 0;
for(arg = 0; arg < g_quickbms_argc; arg++) {
if(!strcmp(g_quickbms_argv[arg], "-9")) do_9 = 0;
if(!strcmp(g_quickbms_argv[arg], "-G")) do_G = 0;
}
for(arg = 0; arg < g_quickbms_argc; arg++) {
myargv[i++] = g_quickbms_argv[arg];
if(!arg) {
if(do_9) myargv[i++] = "-9";
if(do_G) if(g_is_gui == 2) myargv[i++] = "-G"; // auto enabled gui mode, we need to consider that the user used -G in his command-line
}
}
myargv[i] = NULL;
printf("\n\n\n");
spawnv(P_NOWAITO, g_quickbms_arg0, (void *)myargv);
exit(QUICKBMS_ERROR_UNKNOWN); // yeah, no myexit() because we don't need to wait
}
}
myexit(QUICKBMS_ERROR_UNKNOWN);
}
LONG CALLBACK VectoredHandler(EXCEPTION_POINTERS *ExceptionInfo) {
exception_handler(ExceptionInfo);
return EXCEPTION_CONTINUE_SEARCH;
}
LONG WINAPI UnhandledException(EXCEPTION_POINTERS *ExceptionInfo) {
exception_handler(ExceptionInfo);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif
i32 main(i32 argc, char *argv[]) {
static u8 filedir[PATHSZ + 1] = ".", // don't waste the stack
bckdir[PATHSZ + 1] = ".";
files_t *files = NULL;
FILE *fds,
*pre_fd;
time_t benchmark = 0;
int i,
t,
argi,
cmd,
curr_file = 0,
wcx_plugin = 0,
update = 0,
quickbms_outname = 0,
fname_multi_select = 0,
embed_mode = 0;
u8 options_db[256],
*newdir,
*bms,
*fname,
*fdir = ".",
*p,
*tmp,
*pre_script = NULL,
*listfile = NULL,
*filter_files_tmp = NULL,
*filter_in_files_tmp = NULL;
int quickbms_args = 0;
u8 **quickbms_arg = NULL;
#include "quickbms_ver.h"
sprintf(VER, "%d.%d.%d%c", QUICKBMS_VER);
#ifdef WIN32
// useful moreover in future
g_osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&g_osver);
if(!winapi_missing()) {
// disabled because it may cause problems with Win8.1
//SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
//don't enable: if(_AddVectoredContinueHandler) _AddVectoredContinueHandler(1, VectoredHandler);
// my original solution
#ifndef DISABLE_BACKTRACE
g_backtrace_output = calloc(BACKTRACE_BUFFER_MAX, 1);
#endif
//if(_AddVectoredExceptionHandler) _AddVectoredExceptionHandler(1, VectoredHandler);
SetUnhandledExceptionFilter(UnhandledException);
}
#endif
//setbuf(stdout, NULL); // disabled because it's too slow with many files
//setbuf(stderr, NULL); // disabled because it's slow with may Print commands
fflush(stdin); // useless?
#ifdef O_BINARY
setmode(fileno(stdin), O_BINARY);
//setmode(fileno(stdout), O_BINARY);
#endif
srand(time(NULL));
set_codepage();
//xdbg_alloc_extreme();
fprintf(stderr,
"\n"
"QuickBMS generic files extractor and reimporter %s"
#ifdef QUICKBMS64
" (64bit test)"
#endif
"\n"
"by Luigi Auriemma\n"
"e-mail: me@aluigi.org\n"
"web: aluigi.org\n"
" (" __DATE__ " - " __TIME__ ")\n"
"\n"
" quickbms.aluigi.org Homepage\n"
" zenhax.com ZenHAX Forum\n"
" @zenhax Twitter & Scripts\n"
//" @luigi_auriemma aluigi Twitter\n"
"\n",
VER);
#ifdef WIN32
DWORD r;
r = GetModuleFileName(NULL, g_quickbms_arg0, PATHSZ);
if(!r || (r >= PATHSZ))
#endif
mystrcpy(g_quickbms_arg0, argv[0], PATHSZ);
g_quickbms_argc = argc;
g_quickbms_argv = argv;
#ifdef WIN32
int check_if_running_from_doubleclick(void) {
// -1 = error
// 0 = console
// 1 = gui/double-click
if(g_osver.dwMajorVersion > 4) {
// this method is very easy and works well, tested on XP/2003/win7/win8
// doesn't work with win98
#ifndef GWL_WNDPROC
#define GWL_WNDPROC -4
#endif
if(GetWindowLong(GetForegroundWindow(), GWL_WNDPROC)) {
return 1;
}
return 0;
}
// for Win98 only
int ret = -1;
DWORD pid = GetCurrentProcessId();
if(pid) {
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(h != INVALID_HANDLE_VALUE) {
PROCESSENTRY32 pe, pp;
pe.dwSize = sizeof(PROCESSENTRY32);
if(Process32First(h, &pe)) { do {
if(pe.th32ProcessID == pid) {
pp.dwSize = sizeof(PROCESSENTRY32);
if(Process32First(h, &pp)) { do {
if(pp.th32ProcessID == pe.th32ParentProcessID) {
if(!stricmp(get_filename(pp.szExeFile), "winoa386.mod")) ret = 0;
else if(!stricmp(get_filename(pp.szExeFile), "cmd.exe")) ret = 0;
else ret = 1; // found but no command.com, so it's probably explorer.exe
break;
}
} while(Process32Next(h, &pp)); }
break;
}
} while(Process32Next(h, &pe)); }
CloseHandle(h);
}
}
return ret;
}
// necessary to handle the GUI and the secure memory
// before the execption handler that may be used
// in some situations on Win8.1 and bugged software
for(i = 1; i < argc; i++) {
if(verbose_options(argv[i]) < 0) break;
switch(argv[i][1]) {
case 'f': i++; break;
case 'F': i++; break;
case 'L': i++; break;
case 'a': i++; break;
case 's': i++; break;
case 'S': i++; break;
case 'O': i++; break;
case 'M': i++; break;
case 'P': i++; break;
//
case 'G': g_is_gui = !g_is_gui; break;
case '9': XDBG_ALLOC_ACTIVE = !XDBG_ALLOC_ACTIVE; break;
default: break;
}
}
argi = i;
if(check_if_running_from_doubleclick() == 1) g_is_gui = 2;
if(g_is_gui) {
g_quickbms_exception_test = 0;
i = argi;
if(i > argc) i = argc;
i = 3 - (argc - i);
if(i > 0) {
fprintf(stderr,
"- GUI mode activated, remember that the tool works also from command-line\n"
" where are available various options like folder scanning, filters and so on\n"
"\n");
p = calloc(argc + i + 1, sizeof(char *));
if(!p) STD_ERR(QUICKBMS_ERROR_MEMORY);