├── .gitignore ├── .gitmodules ├── Makefile ├── README.md └── source ├── archives.c ├── archives.h ├── cia.c ├── cia.h ├── main.c ├── menu.c ├── menu.h ├── sha1.c ├── sha1.h ├── ttp.c ├── ttp.h ├── utils.c └── utils.h /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | downgrade/ 3 | tmp/ 4 | *.rar 5 | *.3dsx 6 | *.elf 7 | *.smdh 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "source/SuperUserLib3DS"] 2 | path = source/libsu 3 | url = https://github.com/delebile/SuperUserLib3DS.git 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITARM)/3ds_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | # TARGET is the name of the output 14 | # BUILD is the directory where object files & intermediate files will be placed 15 | # SOURCES is a list of directories containing source code 16 | # DATA is a list of directories containing data files 17 | # INCLUDES is a list of directories containing header files 18 | # 19 | # NO_SMDH: if set to anything, no SMDH file is generated. 20 | # ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional) 21 | # APP_TITLE is the name of the app stored in the SMDH file (Optional) 22 | # APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) 23 | # APP_AUTHOR is the author of the app stored in the SMDH file (Optional) 24 | # ICON is the filename of the icon (.png), relative to the project folder. 25 | # If not set, it attempts to use one of the following (in this order): 26 | # - .png 27 | # - icon.png 28 | # - /default_icon.png 29 | #--------------------------------------------------------------------------------- 30 | TARGET := $(notdir $(CURDIR)) 31 | BUILD := build 32 | SOURCES := source source/libsu 33 | DATA := data 34 | INCLUDES := source source/libsu 35 | #ROMFS := romfs 36 | 37 | #--------------------------------------------------------------------------------- 38 | # options for code generation 39 | #--------------------------------------------------------------------------------- 40 | ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft 41 | 42 | CFLAGS := -g -Wall -O2 -mword-relocations \ 43 | -fomit-frame-pointer -ffunction-sections \ 44 | $(ARCH) 45 | 46 | CFLAGS += $(INCLUDE) -DARM11 -D_3DS 47 | 48 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 49 | 50 | ASFLAGS := -g $(ARCH) 51 | LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 52 | 53 | LIBS := -lz -lctru -lm 54 | 55 | #--------------------------------------------------------------------------------- 56 | # list of directories containing libraries, this must be the top level containing 57 | # include and lib 58 | #--------------------------------------------------------------------------------- 59 | LIBDIRS := $(CTRULIB) $(PORTLIBS) 60 | 61 | 62 | #--------------------------------------------------------------------------------- 63 | # no real need to edit anything past this point unless you need to add additional 64 | # rules for different file extensions 65 | #--------------------------------------------------------------------------------- 66 | ifneq ($(BUILD),$(notdir $(CURDIR))) 67 | #--------------------------------------------------------------------------------- 68 | 69 | export OUTPUT := $(CURDIR)/$(TARGET) 70 | export TOPDIR := $(CURDIR) 71 | 72 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 73 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 74 | 75 | export DEPSDIR := $(CURDIR)/$(BUILD) 76 | 77 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 78 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 79 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 80 | PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica))) 81 | SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist))) 82 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 83 | 84 | #--------------------------------------------------------------------------------- 85 | # use CXX for linking C++ projects, CC for standard C 86 | #--------------------------------------------------------------------------------- 87 | ifeq ($(strip $(CPPFILES)),) 88 | #--------------------------------------------------------------------------------- 89 | export LD := $(CC) 90 | #--------------------------------------------------------------------------------- 91 | else 92 | #--------------------------------------------------------------------------------- 93 | export LD := $(CXX) 94 | #--------------------------------------------------------------------------------- 95 | endif 96 | #--------------------------------------------------------------------------------- 97 | 98 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 99 | $(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o) \ 100 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 101 | 102 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 103 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 104 | -I$(CURDIR)/$(BUILD) 105 | 106 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 107 | 108 | ifeq ($(strip $(ICON)),) 109 | icons := $(wildcard *.png) 110 | ifneq (,$(findstring $(TARGET).png,$(icons))) 111 | export APP_ICON := $(TOPDIR)/$(TARGET).png 112 | else 113 | ifneq (,$(findstring icon.png,$(icons))) 114 | export APP_ICON := $(TOPDIR)/icon.png 115 | endif 116 | endif 117 | else 118 | export APP_ICON := $(TOPDIR)/$(ICON) 119 | endif 120 | 121 | ifeq ($(strip $(NO_SMDH)),) 122 | export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh 123 | endif 124 | 125 | ifneq ($(ROMFS),) 126 | export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS) 127 | endif 128 | 129 | .PHONY: $(BUILD) clean all 130 | 131 | #--------------------------------------------------------------------------------- 132 | all: $(BUILD) 133 | 134 | $(BUILD): 135 | @[ -d $@ ] || mkdir -p $@ 136 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 137 | 138 | #--------------------------------------------------------------------------------- 139 | clean: 140 | @echo clean ... 141 | @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf 142 | 143 | 144 | #--------------------------------------------------------------------------------- 145 | else 146 | 147 | DEPENDS := $(OFILES:.o=.d) 148 | 149 | #--------------------------------------------------------------------------------- 150 | # main targets 151 | #--------------------------------------------------------------------------------- 152 | ifeq ($(strip $(NO_SMDH)),) 153 | $(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh 154 | else 155 | $(OUTPUT).3dsx : $(OUTPUT).elf 156 | endif 157 | 158 | $(OUTPUT).elf : $(OFILES) 159 | 160 | #--------------------------------------------------------------------------------- 161 | # you need a rule like this for each extension you use as binary data 162 | #--------------------------------------------------------------------------------- 163 | %.bin.o : %.bin 164 | #--------------------------------------------------------------------------------- 165 | @echo $(notdir $<) 166 | @$(bin2o) 167 | 168 | #--------------------------------------------------------------------------------- 169 | # rules for assembling GPU shaders 170 | #--------------------------------------------------------------------------------- 171 | define shader-as 172 | $(eval CURBIN := $(patsubst %.shbin.o,%.shbin,$(notdir $@))) 173 | picasso -o $(CURBIN) $1 174 | bin2s $(CURBIN) | $(AS) -o $@ 175 | echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h 176 | echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h 177 | echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h 178 | endef 179 | 180 | %.shbin.o : %.v.pica %.g.pica 181 | @echo $(notdir $^) 182 | @$(call shader-as,$^) 183 | 184 | %.shbin.o : %.v.pica 185 | @echo $(notdir $<) 186 | @$(call shader-as,$<) 187 | 188 | %.shbin.o : %.shlist 189 | @echo $(notdir $<) 190 | @$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file))) 191 | 192 | -include $(DEPENDS) 193 | 194 | #--------------------------------------------------------------------------------------- 195 | endif 196 | #--------------------------------------------------------------------------------------- 197 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KernelTimeMachine 2 | [![Project Status](https://img.shields.io/badge/status-in%20progress-yellow.svg)](https://github.com/JustPingo/KernelTimeMachine) 3 | 4 | # LATEST BUILD CONTAINS BRICKING BUGS 100% OF THE TIME 5 | # DO NOT DOWNGRADE WITH IT FOR ANY REASON 6 | 7 | Kernel Time Machine is a work in progress tool to downgrade firmware on the 3DS safely using TPP files. 8 | 9 | Visit [this GBAtemp thread](https://gbatemp.net/threads/clarification-thread-what-is-going-on.407074/) to learn more on what this project is all about. 10 | 11 | ## This is still a WIP. 12 | Please note that there might be some typos and mistakes due to the fact that I'm not using an IDE and did not try to compile it yet. It shouldn't work yet. Please note that the main file is pretty big for now, and will probably get splitted up later on. 13 | 14 | ## DISCLAIMER: 15 | **Run this program at your own risk. I do not recommend running it, even if your 3DS is hardmodded.** 16 | 17 | ## Building 18 | 19 | The program requires [devkitARM](http://devkitpro.org/) and zlib. 20 | 21 | Run the `make` command on the KernelTimeMachine main folder. (If you are on Windows, you can use the msys program incluided in [DevKitPro](http://devkitpro.org/), [MinGW](http://www.mingw.org/) or [Cygwin](http://www.cygwin.com) and on Mac you can use Xcode or [install make manually](http://stackoverflow.com/questions/2556444/install-make-command-without-already-having-make-mac-os-10-5)) 22 | 23 | ## Installing 24 | After building, place the files created by make in the 3ds folder on your SD card and launch it through the [homebrew launcher](http://smealum.github.io/3ds/). 25 | -------------------------------------------------------------------------------- /source/archives.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------------------------------------------------# 2 | #-----------------------------------------------------------------------------------------------------------------------# 3 | #------ This File is Part Of : ----------------------------------------------------------------------------------------# 4 | #------- _ ------------------- ______ _ --------------------------------------------------------------------------# 5 | #------ | | ------------------- (_____ \ | | --------------------------------------------------------------------------# 6 | #------ | | --- _ _ ____ _____) )| | ____ _ _ ____ ____ ----------------------------------------------# 7 | #------ | | --- | | | | / _ | | ____/ | | / _ || | | | / _ ) / ___) ----------------------------------------------# 8 | #------ | |_____| |_| |( ( | | | | | |( ( | || |_| |( (/ / | | --------------------------------------------------# 9 | #------ |_______)\____| \_||_| |_| |_| \_||_| \__ | \____)|_| --------------------------------------------------# 10 | #------------------------------------------------- (____/ -------------------------------------------------------------# 11 | #------------------------ ______ _ -------------------------------------------------------------------------------# 12 | #------------------------ (_____ \ | | -------------------------------------------------------------------------------# 13 | #------------------------ _____) )| | _ _ ___ ------------------------------------------------------------------# 14 | #------------------------ | ____/ | || | | | /___) ------------------------------------------------------------------# 15 | #------------------------ | | | || |_| ||___ | ------------------------------------------------------------------# 16 | #------------------------ |_| |_| \____|(___/ ------------------------------------------------------------------# 17 | #-----------------------------------------------------------------------------------------------------------------------# 18 | #-----------------------------------------------------------------------------------------------------------------------# 19 | #- Licensed under the GPL License --------------------------------------------------------------------------------------# 20 | #-----------------------------------------------------------------------------------------------------------------------# 21 | #- Copyright (c) Nanni ---------------------------------------------------------------------------# 22 | #- Copyright (c) Rinnegatamante -------------------------------------------------------------# 23 | #-----------------------------------------------------------------------------------------------------------------------# 24 | #-----------------------------------------------------------------------------------------------------------------------# 25 | #- Credits : -----------------------------------------------------------------------------------------------------------# 26 | #-----------------------------------------------------------------------------------------------------------------------# 27 | #- Smealum for ctrulib -------------------------------------------------------------------------------------------------# 28 | #- StapleButter for debug font -----------------------------------------------------------------------------------------# 29 | #- Lode Vandevenne for lodepng -----------------------------------------------------------------------------------------# 30 | #- Sean Barrett for stb_truetype ---------------------------------------------------------------------------------------# 31 | #- Special thanks to Aurelio for testing, bug-fixing and various help with codes and implementations -------------------# 32 | #-----------------------------------------------------------------------------------------------------------------------*/ 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "archives.h" 48 | 49 | /****************************************************************************** 50 | ** UnZip ********************************************************************* 51 | *******************************************************************************/ 52 | 53 | #define _ZIP_BUFFER_SIZE (16384) 54 | #define _ZIP_MAX_FILENAME_SIZE (256) 55 | #define _ZIP_CENTRALDIR_ITEM_SIZE (0x2e) 56 | #define _ZIP_LOCALHEADER_SIZE (0x1e) 57 | 58 | #define _ZIP_OK (0) 59 | #define _ZIP_EOF_LIST (-100) 60 | #define _ZIP_ERRNO (Z_ERRNO) 61 | #define _ZIP_EOF (0) 62 | #define _ZIP_PARAM_ERROR (-102) 63 | #define _ZIP_BAD_FILE (-103) 64 | #define _ZIP_INTERNAL_ERROR (-104) 65 | #define _ZIP_CRC_ERROR (-105) 66 | 67 | #define CRC32(c, b) ((*(crc32tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) 68 | #define zdecode(pkeys, crc32tab, c) (ZipUpdateKeys(pkeys, crc32tab, c ^= ZipDecryptByte(pkeys, crc32tab))) 69 | #define _ZIP_BUF_READ_COMMENT (0x400) 70 | 71 | typedef struct 72 | { 73 | unsigned long version; 74 | unsigned long versionneeded; 75 | unsigned long flag; 76 | unsigned long compressionmethod; 77 | unsigned long dosdate; 78 | unsigned long crc; 79 | unsigned long compressedsize; 80 | unsigned long uncompressedsize; 81 | unsigned long filenamesize; 82 | unsigned long fileextrasize; 83 | unsigned long filecommentsize; 84 | unsigned long disknumstart; 85 | unsigned long internalfileattr; 86 | unsigned long externalfileattr; 87 | 88 | } zipFileInfo; 89 | 90 | typedef struct 91 | { 92 | unsigned long currentfileoffset; 93 | 94 | } zipFileInternalInfo; 95 | 96 | typedef struct 97 | { 98 | char *buffer; 99 | z_stream stream; 100 | unsigned long posinzip; 101 | unsigned long streaminitialised; 102 | unsigned long localextrafieldoffset; 103 | unsigned int localextrafieldsize; 104 | unsigned long localextrafieldpos; 105 | unsigned long crc32; 106 | unsigned long crc32wait; 107 | unsigned long restreadcompressed; 108 | unsigned long restreaduncompressed; 109 | FILE* file; 110 | unsigned long compressionmethod; 111 | unsigned long bytebeforezip; 112 | 113 | } zipFileInfoInternal; 114 | 115 | typedef struct 116 | { 117 | unsigned long countentries; 118 | unsigned long commentsize; 119 | 120 | } zipGlobalInfo; 121 | 122 | typedef struct 123 | { 124 | FILE* file; 125 | zipGlobalInfo gi; 126 | unsigned long bytebeforezip; 127 | unsigned long numfile; 128 | unsigned long posincentraldir; 129 | unsigned long currentfileok; 130 | unsigned long centralpos; 131 | unsigned long centraldirsize; 132 | unsigned long centraldiroffset; 133 | zipFileInfo currentfileinfo; 134 | zipFileInternalInfo currentfileinfointernal; 135 | zipFileInfoInternal* currentzipfileinfo; 136 | int encrypted; 137 | unsigned long keys[3]; 138 | const unsigned long* crc32tab; 139 | 140 | } _zip; 141 | 142 | void *MallocPatch(int size) 143 | { 144 | void *ptr = malloc(size); 145 | return ptr; 146 | } 147 | 148 | void FreePatch(void *ptr) 149 | { 150 | if(ptr != NULL) 151 | free(ptr); 152 | } 153 | 154 | static int ZitByte(FILE *file, int *pi) 155 | { 156 | unsigned char c; 157 | 158 | int err = fread(&c, 1, 1, file); 159 | 160 | if(err == 1) 161 | { 162 | *pi = (int)c; 163 | return _ZIP_OK; 164 | } 165 | else 166 | { 167 | if(ferror(file)) 168 | return _ZIP_ERRNO; 169 | else 170 | return _ZIP_EOF; 171 | } 172 | } 173 | 174 | static int ZitShort(FILE *file, unsigned long *px) 175 | { 176 | unsigned long x; 177 | int i = 0; 178 | int err; 179 | 180 | err = ZitByte(file, &i); 181 | x = (unsigned long)i; 182 | 183 | if(err == _ZIP_OK) 184 | err = ZitByte(file, &i); 185 | 186 | x += ((unsigned long)i)<<8; 187 | 188 | if(err == _ZIP_OK) 189 | *px = x; 190 | else 191 | *px = 0; 192 | 193 | return err; 194 | } 195 | 196 | static int ZitLong(FILE *file, unsigned long *px) 197 | { 198 | unsigned long x; 199 | int i = 0; 200 | int err; 201 | 202 | err = ZitByte(file, &i); 203 | x = (unsigned long)i; 204 | 205 | if(err == _ZIP_OK) 206 | err = ZitByte(file, &i); 207 | 208 | x += ((unsigned long)i)<<8; 209 | 210 | if(err == _ZIP_OK) 211 | err = ZitByte(file,&i); 212 | 213 | x += ((unsigned long)i)<<16; 214 | 215 | if(err == _ZIP_OK) 216 | err = ZitByte(file,&i); 217 | 218 | x += ((unsigned long)i)<<24; 219 | 220 | if(err == _ZIP_OK) 221 | *px = x; 222 | else 223 | *px = 0; 224 | 225 | return err; 226 | } 227 | 228 | static int ZipDecryptByte(unsigned long* pkeys, const unsigned long* crc32tab) 229 | { 230 | (void)crc32tab; 231 | 232 | unsigned temp; 233 | 234 | temp = ((unsigned)(*(pkeys + 2)) & 0xffff) | 2; 235 | 236 | return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); 237 | } 238 | 239 | static int ZipUpdateKeys(unsigned long* pkeys, const unsigned long* crc32tab, int c) 240 | { 241 | (*(pkeys + 0)) = CRC32((*(pkeys + 0)), c); 242 | (*(pkeys + 1)) += (*(pkeys + 0)) & 0xff; 243 | (*(pkeys + 1)) = (*(pkeys + 1)) * 134775813L + 1; 244 | 245 | { 246 | register int keyshift = (int)((*(pkeys + 1)) >> 24); 247 | (*(pkeys + 2)) = CRC32((*(pkeys + 2)), keyshift); 248 | } 249 | 250 | return c; 251 | } 252 | 253 | static void ZipInitKeys(const char* passwd, unsigned long* pkeys, const unsigned long* crc32tab) 254 | { 255 | *(pkeys + 0) = 305419896L; 256 | *(pkeys + 1) = 591751049L; 257 | *(pkeys + 2) = 878082192L; 258 | 259 | while(*passwd != '\0') 260 | { 261 | ZipUpdateKeys(pkeys, crc32tab, (int)*passwd); 262 | passwd++; 263 | } 264 | } 265 | 266 | static unsigned long ZipLocateCentralDir(FILE *file) 267 | { 268 | unsigned char* buf; 269 | unsigned long usizefile; 270 | unsigned long ubackread; 271 | unsigned long umaxback = 0xffff; 272 | unsigned long uposfound = 0; 273 | 274 | if(fseek(file, 0, SEEK_END) != 0) 275 | return 0; 276 | 277 | usizefile = ftell(file); 278 | 279 | if(umaxback > usizefile) 280 | umaxback = usizefile; 281 | 282 | buf = (unsigned char*)MallocPatch(_ZIP_BUF_READ_COMMENT + 4); 283 | 284 | if(buf == NULL) 285 | return 0; 286 | 287 | ubackread = 4; 288 | 289 | while(ubackread < umaxback) 290 | { 291 | unsigned long ureadsize, ureadpos; 292 | int i; 293 | 294 | if(ubackread + _ZIP_BUF_READ_COMMENT > umaxback) 295 | ubackread = umaxback; 296 | else 297 | ubackread += _ZIP_BUF_READ_COMMENT; 298 | 299 | ureadpos = usizefile - ubackread; 300 | 301 | ureadsize = ((_ZIP_BUF_READ_COMMENT + 4) < (usizefile - ureadpos)) ? (_ZIP_BUF_READ_COMMENT+ 4) : (usizefile - ureadpos); 302 | 303 | if(fseek(file, ureadpos, SEEK_SET) != 0) 304 | break; 305 | 306 | if(fread(buf, (unsigned int)ureadsize, 1, file) != 1) 307 | break; 308 | 309 | for(i = (int)ureadsize - 3; (i--) > 0;) 310 | 311 | if(((*(buf + i)) == 0x50) && ((*(buf + i + 1)) == 0x4b) && ((*(buf + i + 2)) == 0x05) && ((*(buf + i + 3)) == 0x06)) 312 | { 313 | uposfound = ureadpos + i; 314 | break; 315 | } 316 | 317 | if (uposfound != 0) 318 | break; 319 | } 320 | 321 | FreePatch(buf); 322 | 323 | return uposfound; 324 | } 325 | 326 | static int ZitZipFileInfoInternal(Zip* file, zipFileInfo *pfileinfo, zipFileInternalInfo *pfileinfointernal, char *filename, unsigned long filenamebuffersize, void *extrafield, unsigned long extrafieldbuffersize, char *comment, unsigned long commentbuffersize) 327 | { 328 | _zip* s; 329 | zipFileInfo fileinfo; 330 | zipFileInternalInfo fileinfointernal; 331 | int err = _ZIP_OK; 332 | unsigned long umagic; 333 | long lseek = 0; 334 | 335 | if(file == NULL) 336 | return _ZIP_PARAM_ERROR; 337 | 338 | s = (_zip*)file; 339 | 340 | if(fseek(s->file, s->posincentraldir + s->bytebeforezip, SEEK_SET) != 0) 341 | err = _ZIP_ERRNO; 342 | 343 | if(err == _ZIP_OK) 344 | { 345 | if(ZitLong(s->file, &umagic) != _ZIP_OK) 346 | err = _ZIP_ERRNO; 347 | else if(umagic != 0x02014b50) 348 | err = _ZIP_BAD_FILE; 349 | } 350 | 351 | if (ZitShort(s->file, &fileinfo.version) != _ZIP_OK) 352 | err = _ZIP_ERRNO; 353 | 354 | if (ZitShort(s->file, &fileinfo.versionneeded) != _ZIP_OK) 355 | err = _ZIP_ERRNO; 356 | 357 | if (ZitShort(s->file, &fileinfo.flag) != _ZIP_OK) 358 | err = _ZIP_ERRNO; 359 | 360 | if (ZitShort(s->file, &fileinfo.compressionmethod) != _ZIP_OK) 361 | err = _ZIP_ERRNO; 362 | 363 | if (ZitLong(s->file, &fileinfo.dosdate) != _ZIP_OK) 364 | err = _ZIP_ERRNO; 365 | 366 | if (ZitLong(s->file, &fileinfo.crc) != _ZIP_OK) 367 | err = _ZIP_ERRNO; 368 | 369 | if (ZitLong(s->file, &fileinfo.compressedsize) != _ZIP_OK) 370 | err = _ZIP_ERRNO; 371 | 372 | if (ZitLong(s->file, &fileinfo.uncompressedsize) != _ZIP_OK) 373 | err = _ZIP_ERRNO; 374 | 375 | if (ZitShort(s->file, &fileinfo.filenamesize) != _ZIP_OK) 376 | err = _ZIP_ERRNO; 377 | 378 | if (ZitShort(s->file, &fileinfo.fileextrasize) != _ZIP_OK) 379 | err = _ZIP_ERRNO; 380 | 381 | if (ZitShort(s->file, &fileinfo.filecommentsize) != _ZIP_OK) 382 | err = _ZIP_ERRNO; 383 | 384 | if (ZitShort(s->file, &fileinfo.disknumstart) != _ZIP_OK) 385 | err = _ZIP_ERRNO; 386 | 387 | if (ZitShort(s->file, &fileinfo.internalfileattr) != _ZIP_OK) 388 | err = _ZIP_ERRNO; 389 | 390 | if (ZitLong(s->file, &fileinfo.externalfileattr) != _ZIP_OK) 391 | err = _ZIP_ERRNO; 392 | 393 | if (ZitLong(s->file, &fileinfointernal.currentfileoffset) != _ZIP_OK) 394 | err = _ZIP_ERRNO; 395 | 396 | lseek += fileinfo.filenamesize; 397 | 398 | if((err == _ZIP_OK) && (filename != NULL)) 399 | { 400 | unsigned long usizeread; 401 | 402 | if(fileinfo.filenamesize < filenamebuffersize) 403 | { 404 | *(filename + fileinfo.filenamesize) = '\0'; 405 | usizeread = fileinfo.filenamesize; 406 | } 407 | else 408 | usizeread = filenamebuffersize; 409 | 410 | if((fileinfo.filenamesize > 0) && (filenamebuffersize > 0)) 411 | { 412 | if(fread(filename, (unsigned int)usizeread, 1, s->file) != 1) 413 | err = _ZIP_ERRNO; 414 | } 415 | 416 | lseek -= usizeread; 417 | } 418 | 419 | if((err == _ZIP_OK) && (extrafield != NULL)) 420 | { 421 | unsigned long usizeread; 422 | 423 | if (fileinfo.fileextrasize < extrafieldbuffersize) 424 | usizeread = fileinfo.fileextrasize; 425 | else 426 | usizeread = extrafieldbuffersize; 427 | 428 | if(lseek != 0) 429 | { 430 | if(fseek(s->file, lseek, SEEK_CUR) == 0) 431 | lseek = 0; 432 | else 433 | err = _ZIP_ERRNO; 434 | } 435 | 436 | if((fileinfo.fileextrasize > 0) && (extrafieldbuffersize > 0)) 437 | { 438 | if(fread(extrafield, (unsigned int)usizeread, 1, s->file) != 1) 439 | err = _ZIP_ERRNO; 440 | } 441 | 442 | lseek += fileinfo.fileextrasize - usizeread; 443 | } 444 | else 445 | lseek += fileinfo.fileextrasize; 446 | 447 | if((err == _ZIP_OK) && (comment != NULL)) 448 | { 449 | unsigned long usizeread; 450 | 451 | if(fileinfo.filecommentsize < commentbuffersize) 452 | { 453 | *(comment + fileinfo.filecommentsize) = '\0'; 454 | usizeread = fileinfo.filecommentsize; 455 | } 456 | else 457 | usizeread = commentbuffersize; 458 | 459 | if(lseek != 0) 460 | { 461 | if(fseek(s->file, lseek, SEEK_CUR) == 0) 462 | lseek = 0; 463 | else 464 | err = _ZIP_ERRNO; 465 | } 466 | 467 | if((fileinfo.filecommentsize > 0) && (commentbuffersize > 0)) 468 | { 469 | if(fread(comment, (unsigned int)usizeread, 1, s->file) != 1) 470 | err = _ZIP_ERRNO; 471 | } 472 | 473 | lseek += fileinfo.filecommentsize - usizeread; 474 | } 475 | else 476 | lseek += fileinfo.filecommentsize; 477 | 478 | if((err == _ZIP_OK) && (pfileinfo != NULL)) 479 | *pfileinfo = fileinfo; 480 | 481 | if((err == _ZIP_OK) && (pfileinfointernal != NULL)) 482 | *pfileinfointernal = fileinfointernal; 483 | 484 | return err; 485 | } 486 | 487 | static int ZitGlobalInfo(Zip* file, zipGlobalInfo *zipinfo) 488 | { 489 | _zip* s; 490 | 491 | if(file == NULL) 492 | return _ZIP_PARAM_ERROR; 493 | 494 | s = (_zip*)file; 495 | 496 | *zipinfo = s->gi; 497 | 498 | return _ZIP_OK; 499 | } 500 | 501 | static int ZipGotoFirstFile(Zip* file) 502 | { 503 | int err = _ZIP_OK; 504 | 505 | _zip* s; 506 | 507 | if(file == NULL) 508 | return _ZIP_PARAM_ERROR; 509 | 510 | s = (_zip*)file; 511 | s->posincentraldir = s->centraldiroffset; 512 | s->numfile = 0; 513 | err = ZitZipFileInfoInternal(file, &s->currentfileinfo, &s->currentfileinfointernal, NULL, 0, NULL, 0, NULL, 0); 514 | s->currentfileok = (err == _ZIP_OK); 515 | 516 | return err; 517 | } 518 | 519 | static int ZipCloseCurrentFile(Zip* file) 520 | { 521 | int err = _ZIP_OK; 522 | 523 | _zip* s; 524 | zipFileInfoInternal *pfileinzipreadinfo; 525 | 526 | if(file == NULL) 527 | return _ZIP_PARAM_ERROR; 528 | 529 | s = (_zip*)file; 530 | pfileinzipreadinfo = s->currentzipfileinfo; 531 | 532 | if(pfileinzipreadinfo == NULL) 533 | return _ZIP_PARAM_ERROR; 534 | 535 | if(pfileinzipreadinfo->restreaduncompressed == 0) 536 | { 537 | if(pfileinzipreadinfo->crc32 != pfileinzipreadinfo->crc32wait) 538 | err = _ZIP_CRC_ERROR; 539 | } 540 | 541 | FreePatch(pfileinzipreadinfo->buffer); 542 | pfileinzipreadinfo->buffer = NULL; 543 | 544 | if(pfileinzipreadinfo->streaminitialised) 545 | inflateEnd(&pfileinzipreadinfo->stream); 546 | 547 | pfileinzipreadinfo->streaminitialised = 0; 548 | 549 | FreePatch(pfileinzipreadinfo); 550 | 551 | s->currentzipfileinfo = NULL; 552 | 553 | return err; 554 | } 555 | 556 | static int ZitCurrentFileInfo(Zip* file, zipFileInfo *pfileinfo, char *filename, unsigned long filenamebuffersize, void *extrafield, unsigned long extrafieldbuffersize, char *comment, unsigned long commentbuffersize) 557 | { 558 | return ZitZipFileInfoInternal(file, pfileinfo, NULL, filename, filenamebuffersize, extrafield, extrafieldbuffersize, comment, commentbuffersize); 559 | } 560 | 561 | static int ZipGotoNextFile(Zip* file) 562 | { 563 | _zip* s; 564 | int err; 565 | 566 | if(file == NULL) 567 | return _ZIP_PARAM_ERROR; 568 | 569 | s = (_zip*)file; 570 | 571 | if(!s->currentfileok) 572 | return _ZIP_EOF_LIST; 573 | 574 | if(s->numfile + 1 == s->gi.countentries) 575 | return _ZIP_EOF_LIST; 576 | 577 | s->posincentraldir += _ZIP_CENTRALDIR_ITEM_SIZE + s->currentfileinfo.filenamesize + s->currentfileinfo.fileextrasize + s->currentfileinfo.filecommentsize ; 578 | s->numfile++; 579 | 580 | err = ZitZipFileInfoInternal(file, &s->currentfileinfo, &s->currentfileinfointernal, NULL, 0, NULL, 0, NULL, 0); 581 | 582 | s->currentfileok = (err == _ZIP_OK); 583 | 584 | return err; 585 | } 586 | 587 | static int ZipLocateFile(Zip* file, const char *filename, int casesensitive) 588 | { 589 | (void)casesensitive; 590 | 591 | _zip* s; 592 | int err; 593 | 594 | unsigned long numfilesaved; 595 | unsigned long posincentraldirsaved; 596 | 597 | if(file == NULL) 598 | return _ZIP_PARAM_ERROR; 599 | 600 | if(strlen(filename) >= _ZIP_MAX_FILENAME_SIZE) 601 | return _ZIP_PARAM_ERROR; 602 | 603 | s = (_zip*)file; 604 | 605 | if(!s->currentfileok) 606 | return _ZIP_EOF_LIST; 607 | 608 | numfilesaved = s->numfile; 609 | posincentraldirsaved = s->posincentraldir; 610 | 611 | err = ZipGotoFirstFile(file); 612 | 613 | char currentfilename[_ZIP_MAX_FILENAME_SIZE + 1]; 614 | 615 | while(err == _ZIP_OK) 616 | { 617 | ZitCurrentFileInfo(file,NULL, currentfilename, sizeof(currentfilename) - 1, NULL, 0, NULL, 0); 618 | 619 | if(strcmp(currentfilename, filename) == 0) 620 | return _ZIP_OK; 621 | 622 | err = ZipGotoNextFile(file); 623 | } 624 | 625 | s->numfile = numfilesaved; 626 | s->posincentraldir = posincentraldirsaved; 627 | 628 | return err; 629 | } 630 | 631 | static int ZipCheckCurrentFileCoherencyHeader(_zip *s, unsigned int *pisizevar, unsigned long *poffsetstaticextrafield, unsigned int *psizestaticextrafield) 632 | { 633 | unsigned long umagic, udata, uflags; 634 | unsigned long filenamesize; 635 | unsigned long sizeextrafield; 636 | int err = _ZIP_OK; 637 | 638 | *pisizevar = 0; 639 | *poffsetstaticextrafield = 0; 640 | *psizestaticextrafield = 0; 641 | 642 | if(fseek(s->file, s->currentfileinfointernal.currentfileoffset + s->bytebeforezip, SEEK_SET) != 0) 643 | return _ZIP_ERRNO; 644 | 645 | if(err == _ZIP_OK) 646 | { 647 | if(ZitLong(s->file, &umagic) != _ZIP_OK) 648 | err = _ZIP_ERRNO; 649 | else if(umagic != 0x04034b50) 650 | err = _ZIP_BAD_FILE; 651 | } 652 | 653 | if(ZitShort(s->file, &udata) != _ZIP_OK) 654 | err = _ZIP_ERRNO; 655 | 656 | if(ZitShort(s->file, &uflags) != _ZIP_OK) 657 | err = _ZIP_ERRNO; 658 | 659 | if(ZitShort(s->file, &udata) != _ZIP_OK) 660 | err = _ZIP_ERRNO; 661 | else if((err == _ZIP_OK) && (udata != s->currentfileinfo.compressionmethod)) 662 | err = _ZIP_BAD_FILE; 663 | 664 | if((err == _ZIP_OK) && (s->currentfileinfo.compressionmethod != 0) && (s->currentfileinfo.compressionmethod != Z_DEFLATED)) 665 | err = _ZIP_BAD_FILE; 666 | 667 | if(ZitLong(s->file, &udata) != _ZIP_OK) 668 | err = _ZIP_ERRNO; 669 | 670 | if(ZitLong(s->file, &udata) != _ZIP_OK) 671 | err = _ZIP_ERRNO; 672 | else if((err == _ZIP_OK) && (udata != s->currentfileinfo.crc) && ((uflags & 8) == 0)) 673 | err = _ZIP_BAD_FILE; 674 | 675 | if(ZitLong(s->file, &udata) != _ZIP_OK) 676 | err = _ZIP_ERRNO; 677 | else if((err == _ZIP_OK) && (udata != s->currentfileinfo.compressedsize) && ((uflags & 8) == 0)) 678 | err = _ZIP_BAD_FILE; 679 | 680 | if(ZitLong(s->file, &udata) != _ZIP_OK) 681 | err = _ZIP_ERRNO; 682 | else if((err == _ZIP_OK) && (udata != s->currentfileinfo.uncompressedsize) && ((uflags & 8) == 0)) 683 | err = _ZIP_BAD_FILE; 684 | 685 | if(ZitShort(s->file, &filenamesize) != _ZIP_OK) 686 | err = _ZIP_ERRNO; 687 | else if((err==_ZIP_OK) && (filenamesize != s->currentfileinfo.filenamesize)) 688 | err = _ZIP_BAD_FILE; 689 | 690 | *pisizevar += (unsigned int)filenamesize; 691 | 692 | if(ZitShort(s->file, &sizeextrafield) != _ZIP_OK) 693 | err = _ZIP_ERRNO; 694 | 695 | *poffsetstaticextrafield = s->currentfileinfointernal.currentfileoffset + _ZIP_LOCALHEADER_SIZE + filenamesize; 696 | *psizestaticextrafield = (unsigned int)sizeextrafield; 697 | *pisizevar += (unsigned int)sizeextrafield; 698 | 699 | return err; 700 | } 701 | 702 | static int ZipOpenCurrentFile(Zip* file, const char *password) 703 | { 704 | int err = _ZIP_OK; 705 | int store; 706 | unsigned int isizevar; 707 | _zip* s; 708 | zipFileInfoInternal* pfileinzipreadinfo; 709 | unsigned long localextrafieldoffset; 710 | unsigned int localextrafieldsize; 711 | 712 | char source[12]; 713 | 714 | if(file == NULL) 715 | return _ZIP_PARAM_ERROR; 716 | 717 | s = (_zip*)file; 718 | 719 | if(!s->currentfileok) 720 | return _ZIP_PARAM_ERROR; 721 | 722 | if(s->currentzipfileinfo != NULL) 723 | ZipCloseCurrentFile(file); 724 | 725 | if(ZipCheckCurrentFileCoherencyHeader(s, &isizevar, &localextrafieldoffset, &localextrafieldsize) != _ZIP_OK) 726 | return _ZIP_BAD_FILE; 727 | 728 | pfileinzipreadinfo = (zipFileInfoInternal*) MallocPatch(sizeof(zipFileInfoInternal)); 729 | 730 | if(pfileinzipreadinfo == NULL) 731 | return _ZIP_INTERNAL_ERROR; 732 | 733 | pfileinzipreadinfo->buffer = (char*)MallocPatch(_ZIP_BUFFER_SIZE); 734 | pfileinzipreadinfo->localextrafieldoffset = localextrafieldoffset; 735 | pfileinzipreadinfo->localextrafieldsize = localextrafieldsize; 736 | pfileinzipreadinfo->localextrafieldpos = 0; 737 | 738 | if(pfileinzipreadinfo->buffer == NULL) 739 | { 740 | FreePatch(pfileinzipreadinfo); 741 | return _ZIP_INTERNAL_ERROR; 742 | } 743 | 744 | pfileinzipreadinfo->streaminitialised = 0; 745 | 746 | if((s->currentfileinfo.compressionmethod != 0) && (s->currentfileinfo.compressionmethod != Z_DEFLATED)) 747 | err = _ZIP_BAD_FILE; 748 | 749 | store = s->currentfileinfo.compressionmethod == 0; 750 | 751 | pfileinzipreadinfo->crc32wait = s->currentfileinfo.crc; 752 | pfileinzipreadinfo->crc32 = 0; 753 | pfileinzipreadinfo->compressionmethod = s->currentfileinfo.compressionmethod; 754 | pfileinzipreadinfo->file = s->file; 755 | pfileinzipreadinfo->bytebeforezip = s->bytebeforezip; 756 | 757 | pfileinzipreadinfo->stream.total_out = 0; 758 | 759 | if(!store) 760 | { 761 | pfileinzipreadinfo->stream.zalloc = (alloc_func)0; 762 | pfileinzipreadinfo->stream.zfree = (free_func)0; 763 | pfileinzipreadinfo->stream.opaque = (voidpf)0; 764 | 765 | err = inflateInit2(&pfileinzipreadinfo->stream, -MAX_WBITS); 766 | 767 | if(err == Z_OK) 768 | pfileinzipreadinfo->streaminitialised = 1; 769 | } 770 | 771 | pfileinzipreadinfo->restreadcompressed = s->currentfileinfo.compressedsize; 772 | pfileinzipreadinfo->restreaduncompressed = s->currentfileinfo.uncompressedsize; 773 | 774 | pfileinzipreadinfo->posinzip = s->currentfileinfointernal.currentfileoffset + _ZIP_LOCALHEADER_SIZE + isizevar; 775 | 776 | pfileinzipreadinfo->stream.avail_in = (unsigned int)0; 777 | 778 | s->currentzipfileinfo = pfileinzipreadinfo; 779 | 780 | if(password != NULL) 781 | { 782 | int i; 783 | s->crc32tab = get_crc_table(); 784 | ZipInitKeys(password, s->keys, s->crc32tab); 785 | 786 | if(fseek(pfileinzipreadinfo->file, s->currentzipfileinfo->posinzip + s->currentzipfileinfo->bytebeforezip, SEEK_SET) != 0) 787 | { 788 | FreePatch(pfileinzipreadinfo->buffer); 789 | FreePatch(pfileinzipreadinfo); 790 | 791 | return _ZIP_INTERNAL_ERROR; 792 | } 793 | 794 | if(fread(source, 1, 12, pfileinzipreadinfo->file) < 12) 795 | { 796 | FreePatch(pfileinzipreadinfo->buffer); 797 | FreePatch(pfileinzipreadinfo); 798 | 799 | return _ZIP_INTERNAL_ERROR; 800 | } 801 | 802 | for(i = 0; i < 12; i++) 803 | zdecode(s->keys, s->crc32tab, source[i]); 804 | 805 | s->currentzipfileinfo->posinzip += 12; 806 | s->encrypted = 1; 807 | } 808 | 809 | return _ZIP_OK; 810 | } 811 | 812 | static int ZipReadCurrentFile(Zip* file, void* buf, unsigned int len) 813 | { 814 | int err = _ZIP_OK; 815 | unsigned int iread = 0; 816 | _zip* s; 817 | zipFileInfoInternal* pfileinzipreadinfo; 818 | 819 | if(file == NULL) 820 | return _ZIP_PARAM_ERROR; 821 | 822 | s = (_zip*)file; 823 | pfileinzipreadinfo = s->currentzipfileinfo; 824 | 825 | if(pfileinzipreadinfo == NULL) 826 | return _ZIP_PARAM_ERROR; 827 | 828 | if((pfileinzipreadinfo->buffer == NULL)) 829 | return _ZIP_EOF_LIST; 830 | 831 | if(len == 0) 832 | return 0; 833 | 834 | pfileinzipreadinfo->stream.next_out = (Bytef*)buf; 835 | 836 | pfileinzipreadinfo->stream.avail_out = (unsigned int)len; 837 | 838 | if(len > pfileinzipreadinfo->restreaduncompressed) 839 | pfileinzipreadinfo->stream.avail_out = (unsigned int)pfileinzipreadinfo->restreaduncompressed; 840 | 841 | while(pfileinzipreadinfo->stream.avail_out > 0) 842 | { 843 | if((pfileinzipreadinfo->stream.avail_in == 0) && (pfileinzipreadinfo->restreadcompressed > 0)) 844 | { 845 | unsigned int ureadthis = _ZIP_BUFFER_SIZE; 846 | 847 | if(pfileinzipreadinfo->restreadcompressed < ureadthis) 848 | ureadthis = (unsigned int)pfileinzipreadinfo->restreadcompressed; 849 | 850 | if(ureadthis == 0) 851 | return _ZIP_EOF; 852 | 853 | if(fseek(pfileinzipreadinfo->file, pfileinzipreadinfo->posinzip + pfileinzipreadinfo->bytebeforezip, SEEK_SET) != 0) 854 | return _ZIP_ERRNO; 855 | 856 | if(fread(pfileinzipreadinfo->buffer, ureadthis, 1, pfileinzipreadinfo->file) != 1) 857 | return _ZIP_ERRNO; 858 | 859 | if(s->encrypted) 860 | { 861 | unsigned int i; 862 | 863 | for(i = 0;i < ureadthis;i++) 864 | pfileinzipreadinfo->buffer[i] = zdecode(s->keys, s->crc32tab, pfileinzipreadinfo->buffer[i]); 865 | } 866 | 867 | pfileinzipreadinfo->posinzip += ureadthis; 868 | 869 | pfileinzipreadinfo->restreadcompressed -= ureadthis; 870 | 871 | pfileinzipreadinfo->stream.next_in = (Bytef*)pfileinzipreadinfo->buffer; 872 | pfileinzipreadinfo->stream.avail_in = (unsigned int)ureadthis; 873 | } 874 | 875 | if(pfileinzipreadinfo->compressionmethod == 0) 876 | { 877 | unsigned int udocopy, i; 878 | 879 | if((pfileinzipreadinfo->stream.avail_in == 0) && (pfileinzipreadinfo->restreadcompressed == 0)) 880 | return (iread == 0) ? _ZIP_EOF : iread; 881 | 882 | if(pfileinzipreadinfo->stream.avail_out < pfileinzipreadinfo->stream.avail_in) 883 | udocopy = pfileinzipreadinfo->stream.avail_out; 884 | else 885 | udocopy = pfileinzipreadinfo->stream.avail_in; 886 | 887 | for(i = 0;i < udocopy; i++) 888 | *(pfileinzipreadinfo->stream.next_out + i) = *(pfileinzipreadinfo->stream.next_in + i); 889 | 890 | pfileinzipreadinfo->crc32 = crc32(pfileinzipreadinfo->crc32, pfileinzipreadinfo->stream.next_out, udocopy); 891 | pfileinzipreadinfo->restreaduncompressed -= udocopy; 892 | pfileinzipreadinfo->stream.avail_in -= udocopy; 893 | pfileinzipreadinfo->stream.avail_out -= udocopy; 894 | pfileinzipreadinfo->stream.next_out += udocopy; 895 | pfileinzipreadinfo->stream.next_in += udocopy; 896 | pfileinzipreadinfo->stream.total_out += udocopy; 897 | iread += udocopy; 898 | } 899 | else 900 | { 901 | unsigned long utotaloutbefore, utotaloutafter; 902 | const Bytef *bufbefore; 903 | unsigned long uoutthis; 904 | int flush = Z_SYNC_FLUSH; 905 | 906 | utotaloutbefore = pfileinzipreadinfo->stream.total_out; 907 | bufbefore = pfileinzipreadinfo->stream.next_out; 908 | 909 | err = inflate(&pfileinzipreadinfo->stream, flush); 910 | 911 | utotaloutafter = pfileinzipreadinfo->stream.total_out; 912 | uoutthis = utotaloutafter - utotaloutbefore; 913 | 914 | pfileinzipreadinfo->crc32 = crc32(pfileinzipreadinfo->crc32, bufbefore, (unsigned int)(uoutthis)); 915 | 916 | pfileinzipreadinfo->restreaduncompressed -= uoutthis; 917 | 918 | iread += (unsigned int)(utotaloutafter - utotaloutbefore); 919 | 920 | if(err == Z_STREAM_END) 921 | return (iread == 0) ? _ZIP_EOF : iread; 922 | 923 | if(err != Z_OK) 924 | break; 925 | } 926 | } 927 | 928 | if(err == Z_OK) 929 | return iread; 930 | 931 | return err; 932 | } 933 | 934 | Zip* ZipOpen(const char *filename) 935 | { 936 | //printf("Opening zip\n"); 937 | _zip us; 938 | _zip *s; 939 | unsigned long centralpos, ul; 940 | FILE *file; 941 | 942 | unsigned long numberdisk; 943 | unsigned long numberdiskwithCD; 944 | unsigned long numberentryCD; 945 | 946 | int err = _ZIP_OK; 947 | 948 | file = fopen(filename, "rb"); 949 | 950 | if(file == NULL) 951 | return NULL; 952 | 953 | centralpos = ZipLocateCentralDir(file); 954 | 955 | if(centralpos == 0) 956 | err = _ZIP_ERRNO; 957 | 958 | if(fseek(file, centralpos, SEEK_SET) != 0) 959 | err = _ZIP_ERRNO; 960 | 961 | if(ZitLong(file, &ul) != _ZIP_OK) 962 | err = _ZIP_ERRNO; 963 | 964 | if(ZitShort(file, &numberdisk) != _ZIP_OK) 965 | err = _ZIP_ERRNO; 966 | 967 | if(ZitShort(file, &numberdiskwithCD) != _ZIP_OK) 968 | err = _ZIP_ERRNO; 969 | 970 | if(ZitShort(file, &us.gi.countentries) != _ZIP_OK) 971 | err = _ZIP_ERRNO; 972 | 973 | if(ZitShort(file, &numberentryCD) != _ZIP_OK) 974 | err = _ZIP_ERRNO; 975 | 976 | if((numberentryCD != us.gi.countentries) || (numberdiskwithCD != 0) || (numberdisk != 0)) 977 | err = _ZIP_BAD_FILE; 978 | 979 | if(ZitLong(file, &us.centraldirsize) != _ZIP_OK) 980 | err = _ZIP_ERRNO; 981 | 982 | if(ZitLong(file, &us.centraldiroffset) != _ZIP_OK) 983 | err = _ZIP_ERRNO; 984 | 985 | if(ZitShort(file, &us.gi.commentsize) != _ZIP_OK) 986 | err = _ZIP_ERRNO; 987 | 988 | if((centralpos < us.centraldiroffset + us.centraldirsize) && (err == _ZIP_OK)) 989 | err = _ZIP_BAD_FILE; 990 | 991 | if(err != _ZIP_OK) 992 | { 993 | fclose(file); 994 | return NULL; 995 | } 996 | 997 | us.file = file; 998 | us.bytebeforezip = centralpos - (us.centraldiroffset + us.centraldirsize); 999 | us.centralpos = centralpos; 1000 | us.currentzipfileinfo = NULL; 1001 | us.encrypted = 0; 1002 | 1003 | s = (_zip*)MallocPatch(sizeof(_zip)); 1004 | 1005 | *s = us; 1006 | 1007 | ZipGotoFirstFile((Zip*)s); 1008 | 1009 | return(Zip*)s; 1010 | } 1011 | 1012 | int ZipClose(Zip* zip) 1013 | { 1014 | _zip* s; 1015 | 1016 | if(zip == NULL) 1017 | return 0; 1018 | 1019 | s = (_zip*)zip; 1020 | 1021 | if(s->currentzipfileinfo != NULL) 1022 | ZipCloseCurrentFile(zip); 1023 | 1024 | fclose(s->file); 1025 | 1026 | FreePatch(s); 1027 | 1028 | return 1; 1029 | } 1030 | 1031 | int ZipExtractCurrentFile(Zip *zip, int *nopath, const char *password) 1032 | { 1033 | //void(overwrite); 1034 | 1035 | char filenameinzip[256]; 1036 | char *filenameWithoutPath; 1037 | char *p; 1038 | void *buffer; 1039 | unsigned int buffersize = 64*1024; 1040 | int err = 0; 1041 | 1042 | FILE *fout = NULL; 1043 | 1044 | zipFileInfo fileInfo; 1045 | 1046 | err = ZitCurrentFileInfo(zip, &fileInfo, filenameinzip, sizeof(filenameinzip), NULL, 0, NULL, 0); 1047 | 1048 | if(err != 0) 1049 | { 1050 | printf("error %d with zipfile in ZitCurrentFileInfo\n", err); 1051 | return -1; 1052 | } 1053 | 1054 | buffer = (void *)MallocPatch(buffersize); 1055 | 1056 | if(!buffer) 1057 | { 1058 | printf("Error allocating buffer\n"); 1059 | 1060 | return 0; 1061 | } 1062 | 1063 | p = filenameWithoutPath = filenameinzip; 1064 | 1065 | while((*p) != '\0') 1066 | { 1067 | if(((*p) == '/') || ((*p) == '\\')) 1068 | filenameWithoutPath = p + 1; 1069 | 1070 | p++; 1071 | } 1072 | 1073 | if((*filenameWithoutPath) == '\0') 1074 | { 1075 | if((*nopath) == 0) 1076 | { 1077 | //printf("Creating directory: %s\n", filenameinzip); 1078 | mkdir(filenameinzip, 0777); 1079 | } 1080 | } 1081 | else 1082 | { 1083 | const char *writeFilename; 1084 | 1085 | if((*nopath) == 0) 1086 | writeFilename = filenameinzip; 1087 | else 1088 | writeFilename = filenameWithoutPath; 1089 | 1090 | err = ZipOpenCurrentFile(zip, password); 1091 | 1092 | if(err != _ZIP_OK) 1093 | printf("Error with zipfile in ZipOpenCurrentFile\n"); 1094 | 1095 | fout = fopen(writeFilename, "wb"); 1096 | 1097 | if((fout == NULL) && ((*nopath) == 0) && (filenameWithoutPath != (char *)filenameinzip)) 1098 | { 1099 | char c = *(filenameWithoutPath - 1); 1100 | *(filenameWithoutPath - 1) = '\0'; 1101 | mkdir(writeFilename, 0777); 1102 | *(filenameWithoutPath - 1) = c; 1103 | fout = fopen(writeFilename, "wb"); 1104 | } 1105 | 1106 | if(fout == NULL) 1107 | printf("Error opening file\n"); 1108 | 1109 | do 1110 | { 1111 | err = ZipReadCurrentFile(zip, buffer, buffersize); 1112 | 1113 | if(err < 0) 1114 | { 1115 | printf("Error with zipfile in ZipReadCurrentFile\n"); 1116 | break; 1117 | } 1118 | 1119 | if(err > 0) 1120 | { 1121 | fwrite(buffer, 1, err, fout); 1122 | } 1123 | 1124 | } while (err > 0); 1125 | 1126 | fclose(fout); 1127 | 1128 | err = ZipCloseCurrentFile(zip); 1129 | 1130 | if(err != _ZIP_OK) 1131 | printf("Error with zipfile in ZipCloseCurrentFile\n"); 1132 | } 1133 | 1134 | if(buffer) 1135 | FreePatch(buffer); 1136 | 1137 | return err; 1138 | } 1139 | 1140 | int ZipExtract(Zip* zip, const char *password) 1141 | { 1142 | unsigned int i; 1143 | zipGlobalInfo gi; 1144 | memset(&gi, 0, sizeof(zipGlobalInfo)); 1145 | int err; 1146 | int nopath = 0; 1147 | 1148 | err = ZitGlobalInfo(zip, &gi); 1149 | 1150 | if(err != _ZIP_OK) 1151 | printf("Error with zipfile in ZitGlobalInfo\n"); 1152 | 1153 | for(i = 0;i < gi.countentries;i++) 1154 | { 1155 | if(ZipExtractCurrentFile(zip, &nopath, password) != _ZIP_OK) 1156 | break; 1157 | 1158 | if((i + 1) < gi.countentries) 1159 | { 1160 | err = ZipGotoNextFile(zip); 1161 | 1162 | if(err != _ZIP_OK) 1163 | printf("Error with zipfile in ZipGotoNextFile\n"); 1164 | } 1165 | } 1166 | 1167 | return err; 1168 | } 1169 | 1170 | ZipFile* ZipFileRead(Zip* zip, const char *filename, const char *password) 1171 | { 1172 | char filenameinzip[256]; 1173 | int err = 0; 1174 | 1175 | ZipFile* zipfile = (ZipFile*) MallocPatch(sizeof(ZipFile)); 1176 | 1177 | if(!zipfile) 1178 | return NULL; 1179 | 1180 | if(ZipLocateFile(zip, filename, 0) != 0) 1181 | { 1182 | FreePatch(zipfile); 1183 | return NULL; 1184 | } 1185 | 1186 | zipFileInfo fileinfo; 1187 | 1188 | err = ZitCurrentFileInfo(zip, &fileinfo, filenameinzip, sizeof(filenameinzip), NULL, 0, NULL, 0); 1189 | 1190 | if(err != 0) 1191 | { 1192 | printf("error %d with zipfile in ZitCurrentFileInfo\n", err); 1193 | FreePatch(zipfile); 1194 | return NULL; 1195 | } 1196 | 1197 | err = ZipOpenCurrentFile(zip, password); 1198 | 1199 | if(err != 0) 1200 | { 1201 | printf("error %d with zipfile in ZipOpenCurrentFile\n", err); 1202 | FreePatch(zipfile); 1203 | return NULL; 1204 | } 1205 | 1206 | zipfile->size = fileinfo.uncompressedsize; 1207 | 1208 | zipfile->data = (unsigned char*)MallocPatch(fileinfo.uncompressedsize); 1209 | 1210 | if(!zipfile->data) 1211 | { 1212 | printf("error allocating data for zipfile\n"); 1213 | FreePatch(zipfile); 1214 | return NULL; 1215 | } 1216 | 1217 | unsigned int count = 0; 1218 | err = 1; 1219 | 1220 | while(err > 0) 1221 | { 1222 | err = ZipReadCurrentFile(zip, &zipfile->data[count], fileinfo.uncompressedsize); 1223 | 1224 | if(err < 0) 1225 | { 1226 | printf("error %d with zipfile in ZipReadCurrentFile\n", err); 1227 | break; 1228 | } 1229 | else 1230 | count += err; 1231 | } 1232 | 1233 | if(err == 0) 1234 | { 1235 | err = ZipCloseCurrentFile(zip); 1236 | 1237 | if(err != 0) 1238 | { 1239 | printf("error %d with zipfile in ZipCloseCurrentFile\n", err); 1240 | FreePatch(zipfile->data); 1241 | FreePatch(zipfile); 1242 | return NULL; 1243 | } 1244 | 1245 | return zipfile; 1246 | } 1247 | else 1248 | { 1249 | ZipCloseCurrentFile(zip); 1250 | FreePatch(zipfile->data); 1251 | FreePatch(zipfile); 1252 | 1253 | return NULL; 1254 | } 1255 | } 1256 | 1257 | void ZipFileFree(ZipFile* file) 1258 | { 1259 | if(file->data) 1260 | FreePatch(file->data); 1261 | 1262 | if(file) 1263 | FreePatch(file); 1264 | } 1265 | 1266 | #ifdef __cplusplus 1267 | } 1268 | #endif 1269 | -------------------------------------------------------------------------------- /source/archives.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------------------------------------------------# 2 | #-----------------------------------------------------------------------------------------------------------------------# 3 | #------ This File is Part Of : ----------------------------------------------------------------------------------------# 4 | #------- _ ------------------- ______ _ --------------------------------------------------------------------------# 5 | #------ | | ------------------- (_____ \ | | --------------------------------------------------------------------------# 6 | #------ | | --- _ _ ____ _____) )| | ____ _ _ ____ ____ ----------------------------------------------# 7 | #------ | | --- | | | | / _ | | ____/ | | / _ || | | | / _ ) / ___) ----------------------------------------------# 8 | #------ | |_____| |_| |( ( | | | | | |( ( | || |_| |( (/ / | | --------------------------------------------------# 9 | #------ |_______)\____| \_||_| |_| |_| \_||_| \__ | \____)|_| --------------------------------------------------# 10 | #------------------------------------------------- (____/ -------------------------------------------------------------# 11 | #------------------------ ______ _ -------------------------------------------------------------------------------# 12 | #------------------------ (_____ \ | | -------------------------------------------------------------------------------# 13 | #------------------------ _____) )| | _ _ ___ ------------------------------------------------------------------# 14 | #------------------------ | ____/ | || | | | /___) ------------------------------------------------------------------# 15 | #------------------------ | | | || |_| ||___ | ------------------------------------------------------------------# 16 | #------------------------ |_| |_| \____|(___/ ------------------------------------------------------------------# 17 | #-----------------------------------------------------------------------------------------------------------------------# 18 | #-----------------------------------------------------------------------------------------------------------------------# 19 | #- Licensed under the GPL License --------------------------------------------------------------------------------------# 20 | #-----------------------------------------------------------------------------------------------------------------------# 21 | #- Copyright (c) Nanni --------------------------------------------------------------------------# 22 | #- Copyright (c) Rinnegatamante -----------------------------------------------------# 23 | #-----------------------------------------------------------------------------------------------------------------------# 24 | #- Official Forum : http://rinnegatamante.eu/luaplayerplus/forum.php ---------------------------------------------------# 25 | #- For help using LuaPlayerPlus, code help, and other please visit : http://rinnegatamante.eu/luaplayerplus/forum.php --# 26 | #-----------------------------------------------------------------------------------------------------------------------# 27 | #- Credits : -----------------------------------------------------------------------------------------------------------# 28 | #-----------------------------------------------------------------------------------------------------------------------# 29 | #- Homemister for LPHM sourcecode --------------------------------------------------------------------------------------# 30 | #- Zack & Shine for LP Euphoria sourcecode -----------------------------------------------------------------------------# 31 | #- ab5000 for support on psp-ita.com -----------------------------------------------------------------------------------# 32 | #- valantin for sceIoMvdir and sceIoCpdir improved functions------------------------------------------------------------# 33 | #- Dark_AleX for usbdevice ---------------------------------------------------------------------------------------------# 34 | #- VirtuosFlame & ColdBird for iso drivers and kuBridge ----------------------------------------------------------------# 35 | #- sakya for Media Engine and OslibMod ---------------------------------------------------------------------------------# 36 | #- Booster & silverspring for EEPROM write/read functions --------------------------------------------------------------# 37 | #- Akind for RemoteJoyLite ---------------------------------------------------------------------------------------------# 38 | #- cooleyes for mpeg4 lib ----------------------------------------------------------------------------------------------# 39 | #- Arshia001 for PSPAALib ----------------------------------------------------------------------------------------------# 40 | #- InsertWittyName & MK2k for PGE sourcecode ---------------------------------------------------------------------------# 41 | #- Youresam for LUA BMPLib ---------------------------------------------------------------------------------------------# 42 | #- Raphael for vram manager code ---------------------------------------------------------------------------------------# 43 | #- Dynodzzo for LSD concepts -------------------------------------------------------------------------------------------# 44 | #- ab_portugal for Image.negative function -----------------------------------------------------------------------------# 45 | #- JiC� for drawCircle function ----------------------------------------------------------------------------------------# 46 | #- Rapper_skull & DarkGiovy for testing LuaPlayer Plus and coming up with some neat ideas for it. ----------------------# 47 | #-----------------------------------------------------------------------------------------------------------------------# 48 | #-----------------------------------------------------------------------------------------------------------------------# 49 | #-----------------------------------------------------------------------------------------------------------------------# 50 | #-----------------------------------------------------------------------------------------------------------------------*/ 51 | 52 | #ifndef __ARCHIVES_H_ 53 | #define __ARCHIVES_H_ 54 | 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | 59 | /****************************************************************************** 60 | ** UnZip ********************************************************************* 61 | *******************************************************************************/ 62 | 63 | /** @defgroup Zip Zip Library 64 | * @{ 65 | */ 66 | 67 | #include 68 | 69 | /** 70 | * A zip 71 | */ 72 | typedef void Zip; 73 | 74 | /** 75 | * A file within a zip 76 | */ 77 | typedef struct 78 | { 79 | unsigned char *data; /**< The file data */ 80 | int size; /**< Size of the data */ 81 | 82 | } ZipFile; 83 | 84 | /** 85 | * Open a Zip file 86 | * 87 | * @param filename - Path of the zip to load. 88 | * 89 | * @returns A pointer to a ::Zip struct or NULL on error. 90 | */ 91 | Zip* ZipOpen(const char *filename); 92 | 93 | /** 94 | * Close a Zip file 95 | * 96 | * @param zip - A valid (previously opened) ::Zip 97 | * 98 | * @returns 1 on success, 0 on error 99 | */ 100 | int ZipClose(Zip *zip); 101 | 102 | /** 103 | * Read a file from a zip 104 | * 105 | * @param zip - A valid (previously opened) ::Zip 106 | * 107 | * @param filename - The file to read within the zip 108 | * 109 | * @param password - The password of the file (pass NULL if no password) 110 | * 111 | * @returns A ::ZipFile struct containing the file 112 | */ 113 | ZipFile* ZipFileRead(Zip *zip, const char *filename, const char *password); 114 | 115 | /** 116 | * Extract all files from a zip 117 | * 118 | * @param zip - A valid (previously opened) ::Zip file 119 | * 120 | * @param password - The password of the file (pass NULL if no password) 121 | * 122 | * @returns 1 on success, 0 on error. 123 | */ 124 | int ZipExtract(Zip *zip, const char *password); 125 | 126 | /** 127 | * Free the file data previously loaded from a zip 128 | * 129 | * @param file - A valid (previously read) ::ZipFile 130 | */ 131 | void ZipFileFree(ZipFile *file); 132 | 133 | #ifdef __cplusplus 134 | } 135 | #endif 136 | 137 | #endif /* __ARCHIVES_H_ */ 138 | 139 | /*----------------------------------------------------------------------------------------------------------------------# 140 | #-----------------------------------------------------------------------------------------------------------------------*/ -------------------------------------------------------------------------------- /source/cia.c: -------------------------------------------------------------------------------- 1 | #include <3ds.h> 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // KernelTimeMachine 8 | // Safe CIA manager 9 | // Licensed under GNU General Public License (GPL) 10 | // Check out https://www.gnu.org/licenses/gpl.html 11 | 12 | bool pendingFirm = false; 13 | char* firmPendingPath; 14 | u8 firmPendingMediatype; 15 | char* firmPendingName; 16 | bool firmPendingAllowSafeTitles; 17 | 18 | bool checkIfInstalled(u8 mediatype, u64 titleID) { 19 | 20 | u32 titlesAmount; 21 | AM_GetTitleCount(mediatype, &titlesAmount); 22 | u64* titleIDs = malloc(sizeof(u64) * titlesAmount); 23 | AM_GetTitleIdList(mediatype, titlesAmount, titleIDs); 24 | 25 | u32 i; 26 | for (i = 0; i < titlesAmount; i++) { 27 | if (titleIDs[i] == titleID) { 28 | free(titleIDs); 29 | return true; 30 | } 31 | } 32 | 33 | free(titleIDs); 34 | return false; 35 | 36 | } 37 | 38 | bool installCIA(char* path, u8 mediatype, char* name, bool allowSafeTitles) { 39 | 40 | Result res; 41 | FS_Archive archive = {ARCHIVE_SDMC, {PATH_EMPTY, 0, 0}}; 42 | FSUSER_OpenArchive(&archive); 43 | Handle ciaHandle; 44 | Handle ciaFileHandle; 45 | AM_TitleEntry ciaInfo; 46 | 47 | // It may be possible to use `FSUSER_OpenFileDirectly` 48 | FSUSER_OpenFile(&ciaFileHandle, archive, fsMakePath(PATH_ASCII, path), FS_OPEN_READ, 0); 49 | res = AM_GetCiaFileInfo(mediatype, &ciaInfo, ciaFileHandle); 50 | FSFILE_Close(ciaFileHandle); 51 | FSUSER_CloseArchive(&archive); 52 | if (res) return false; 53 | 54 | if (ciaInfo.titleID == 0x000400102002CA00LL) return true; // ignore that bricking title 55 | 56 | if ((ciaInfo.titleID & 0xFF) == 0x03 && !allowSafeTitles) return true; // ignore SAFE_MODE titles if it should 57 | if ((ciaInfo.titleID & 0xFF) != 0x03 && allowSafeTitles) return true; // ignore normal titles if it should 58 | 59 | if (ciaInfo.titleID == 0x0004013800000002LL || ciaInfo.titleID == 0x0004013820000002LL) { // if you're trying to install NATIVE_FIRM, pends it 60 | firmPendingPath = malloc(strlen(path)); 61 | strcpy(firmPendingPath, path); 62 | firmPendingMediatype = mediatype; 63 | firmPendingName = malloc(strlen(name)); 64 | strcpy(firmPendingName, name); 65 | firmPendingAllowSafeTitles = allowSafeTitles; 66 | pendingFirm = true; 67 | return true; 68 | } 69 | 70 | printf("Installing %s...\n", name); 71 | 72 | FILE* file = fopen(path, "rb"); 73 | if (!file) return false; 74 | 75 | if (checkIfInstalled(mediatype, ciaInfo.titleID)) { 76 | if (ciaInfo.titleID >> 32 & 0xFFFF) AM_DeleteTitle(mediatype, ciaInfo.titleID); 77 | else AM_DeleteAppTitle(mediatype, ciaInfo.titleID); 78 | } 79 | 80 | res = AM_StartCiaInstall(mediatype, &ciaHandle); 81 | if (res) return false; 82 | 83 | fseek(file, 0, SEEK_END); 84 | off_t size = ftell(file); 85 | fseek(file, 0, SEEK_SET); 86 | u32 blockAmount = size / 0x160000; // Finds how many blocks of 4MB you have in the file 87 | char* block = malloc(0x160000); 88 | u32* bytesWritten = 0; 89 | u32 i; 90 | for (i = 0; i < blockAmount; i++) { 91 | fread(block, 1, 0x160000, file); 92 | FSFILE_Write(ciaHandle, bytesWritten, 0x160000*i, block, 0x160000, 0); 93 | } 94 | 95 | if (size % 0x160000 != 0) { 96 | fread(block, 1, size-0x160000*blockAmount, file); 97 | FSFILE_Write(ciaHandle, bytesWritten, 0x160000*blockAmount, block, size-0x160000*blockAmount, 0); 98 | } 99 | 100 | free(block); 101 | 102 | res = AM_FinishCiaInstall(mediatype, &ciaHandle); 103 | if (res) return false; 104 | 105 | if (!checkIfInstalled(mediatype, ciaInfo.titleID)) return false; 106 | 107 | return true; 108 | 109 | } 110 | 111 | bool installFIRM(char* path, u8 mediatype, char* name, bool allowSafeTitles) { 112 | 113 | Result res; 114 | FS_Archive archive = {ARCHIVE_SDMC, {PATH_EMPTY, 0, 0}}; 115 | FSUSER_OpenArchive(&archive); 116 | Handle ciaHandle; 117 | Handle ciaFileHandle; 118 | AM_TitleEntry ciaInfo; 119 | 120 | FSUSER_OpenFile(&ciaFileHandle, archive, fsMakePath(PATH_ASCII, path), FS_OPEN_READ, 0); 121 | res = AM_GetCiaFileInfo(mediatype, &ciaInfo, ciaFileHandle); 122 | FSFILE_Close(ciaFileHandle); 123 | FSUSER_CloseArchive(&archive); 124 | if (res) return false; 125 | 126 | if ((ciaInfo.titleID & 0xFF) == 0x03 && !allowSafeTitles) return true; // ignore SAFE_MODE titles if it should 127 | 128 | printf("Installing FIRM %s...\n", name); 129 | 130 | FILE* file = fopen(path, "rb"); 131 | if (!file) return false; 132 | 133 | if (ciaInfo.titleID >> 32 & 0xFFFF) AM_DeleteTitle(mediatype, ciaInfo.titleID); 134 | else AM_DeleteAppTitle(mediatype, ciaInfo.titleID); 135 | 136 | res = AM_StartCiaInstall(mediatype, &ciaHandle); 137 | if (res) return false; 138 | 139 | fseek(file, 0, SEEK_END); 140 | off_t size = ftell(file); 141 | fseek(file, 0, SEEK_SET); 142 | u32 blockAmount = size / 0x160000; // Finds how many blocks of 4MB you have in the file 143 | char* block = malloc(0x160000); 144 | u32* bytesWritten = 0; 145 | u32 i; 146 | for (i = 0; i < blockAmount; i++) { 147 | fread(block, 1, 0x160000, file); 148 | FSFILE_Write(ciaHandle, bytesWritten, 0x160000*i, block, 0x160000, 0); 149 | } 150 | 151 | if (size % 0x160000 != 0) { 152 | fread(block, 1, size-0x160000*blockAmount, file); 153 | FSFILE_Write(ciaHandle, bytesWritten, 0x160000*blockAmount, block, size-0x160000*blockAmount, 0); 154 | } 155 | 156 | free(block); 157 | 158 | res = AM_FinishCiaInstall(mediatype, &ciaHandle); 159 | if (res) return false; 160 | 161 | AM_InstallFirm(ciaInfo.titleID); 162 | 163 | return true; 164 | } 165 | 166 | /** 167 | * Returns true if a FIRM install is delayed (pending) 168 | */ 169 | bool isFirmPending() { 170 | return pendingFirm; 171 | } 172 | 173 | /** 174 | * Installs the FIRM that installCIA() delayed installation 175 | */ 176 | bool installPendingFIRM() { 177 | 178 | if (!pendingFirm) return false; 179 | 180 | // Tries to install the FIRM 5 times before abandon 181 | for (u8 i = 0; i < 5 && !installFIRM(firmPendingPath, firmPendingMediatype, firmPendingName, firmPendingAllowSafeTitles); i++); 182 | 183 | pendingFirm = false; 184 | free(firmPendingPath); 185 | free(firmPendingName); 186 | 187 | return true; 188 | } 189 | -------------------------------------------------------------------------------- /source/cia.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // KernelTimeMachine 3 | // Safe CIA manager 4 | // Licensed under GNU General Public License (GPL) 5 | // Check out https://www.gnu.org/licenses/gpl.html 6 | 7 | bool checkIfInstalled(u8 mediatype, u64 titleID); 8 | bool installCIA(char *path, u8 mediatype, char *name, bool allowSafeTitles); 9 | bool installFIRM(char *path, u8 mediatype, char *name, bool allowSafeTitles); 10 | bool installPendingFIRM(); 11 | bool isFirmPending(); 12 | -------------------------------------------------------------------------------- /source/main.c: -------------------------------------------------------------------------------- 1 | #include <3ds.h> 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "archives.h" 7 | #include "sha1.h" 8 | #include "utils.h" 9 | #include "cia.h" 10 | #include "ttp.h" 11 | #include "menu.h" 12 | #include "libsu/libsu.h" 13 | 14 | // KernelTimeMachine 15 | // Safe CIA manager 16 | // Licensed under GNU General Public License (GPL) 17 | // Check out https://www.gnu.org/licenses/gpl.html 18 | 19 | int main() { 20 | gfxInitDefault(); 21 | consoleInit(GFX_TOP, &topConsole); 22 | consoleSelect(&topConsole); 23 | hidInit(); 24 | if (suInit() == -1) { 25 | printf("\nError while performing kernel11 exploit.\nPlease try again. Press (START) to exit."); 26 | 27 | u32 kDown; 28 | while (aptMainLoop()) { 29 | hidScanInput(); 30 | kDown = hidKeysDown(); 31 | if (kDown & KEY_START) break; 32 | } 33 | return -1; 34 | } 35 | 36 | cfguInit(); 37 | fsInit(); 38 | amInit(); 39 | 40 | fbTopLeft = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); 41 | fbTopRight = gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL); 42 | fbBottom = gfxGetFramebuffer(GFX_BOTTOM, 0, NULL, NULL); 43 | 44 | u8 next = mainMenu(); 45 | while (aptMainLoop()) { 46 | switch (next) { 47 | case 0: break; 48 | case 1: next = mainMenu(); break; 49 | //case 2: next = legitInstallMenu(); break; 50 | case 3: next = downgradeMenu(false); break; 51 | //case 4: next = downgradeMSETMenu(); break; 52 | //case 5: next = downgradeBrowserMenu(); break; 53 | case 6: next = downgradeMenu(true); break; 54 | default: next = mainMenu(); 55 | } 56 | if (next == 0) break; 57 | } 58 | 59 | gfxExit(); 60 | return 0; 61 | } 62 | 63 | /*void KernelTimeMachine(Handle amHandle) { 64 | 65 | am = (amHandle == NULL ? (amInit() == 0 ? *amGetSessionHandle() : NULL) : amHandle); 66 | if (am == NULL) return; 67 | main(); 68 | 69 | }*/ 70 | -------------------------------------------------------------------------------- /source/menu.c: -------------------------------------------------------------------------------- 1 | #include <3ds.h> 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "ttp.h" 7 | #include "utils.h" 8 | #include "sha1.h" 9 | 10 | // KernelTimeMachine 11 | // Safe CIA manager 12 | // Licensed under GNU General Public License (GPL) 13 | // Check out https://www.gnu.org/licenses/gpl.html 14 | 15 | PrintConsole topConsole; 16 | PrintConsole botConsole; 17 | 18 | u8 downgradeMenu(bool safeMode) { 19 | Result res; 20 | u32 kDown; 21 | u16 timer = 255; 22 | bool shouldNotChange = true; 23 | bool canContinue = false; 24 | while (aptMainLoop() && !canContinue) { 25 | consoleClear(); 26 | clearScreens(); 27 | printf("FIRMWARE DOWNGRADE\n\n"); 28 | printf("WARNING!\n"); 29 | printf("YOU ARE ENTERING A DANGEROUS PROCESS!\n"); 30 | printf("Please read those instructions\nbefore trying anything.\n\n"); 31 | if (safeMode) printf("DO NOT DO THIS IF YOU HAVEN'T\nDONE A NORMAL DOWNGRADE YET."); 32 | printf("DO NOT turn off you console during\nthe process: it WILL brick.\n"); 33 | printf("DO NOT get to HomebrewMenu during\nthe process: it WILL brick.\n"); 34 | printf("DO NOT remove the SD card during\nthe process: it WILL brick.\n"); 35 | printf("DO NOT throw off your 3DS during\nthe process: it WILL break.\n"); 36 | printf("PLUG your charger in, and have\nsome energy in your battery.\n\n"); 37 | printf("Press (B) to get back.\n"); 38 | 39 | if (timer > 1) { 40 | printf("Please read the instructions to continue.\n\n"); 41 | } else { 42 | printf("Press (A) to proceed."); 43 | } 44 | 45 | while (aptMainLoop() && !canContinue && shouldNotChange) { 46 | 47 | if (timer > 1) timer--; 48 | else { if (timer == 1) shouldNotChange = false; } 49 | 50 | hidScanInput(); 51 | kDown = hidKeysDown(); 52 | if (kDown & KEY_B) 53 | return 1; 54 | if ((kDown & KEY_A) && timer == 0) 55 | canContinue = true; 56 | } 57 | shouldNotChange = true; 58 | timer = 0; 59 | } 60 | 61 | if (!canContinue) return 0; 62 | 63 | u32 firmware = osGetFirmVersion(); // according to some tests, this does not work 64 | u32 major = GET_VERSION_MAJOR(firmware); // doesn't matter really, will be deleted if it sucks 65 | u32 minor = GET_VERSION_MINOR(firmware); 66 | u32 rev = GET_VERSION_REVISION(firmware); 67 | 68 | u8 region = 0; 69 | u8 model = 0; 70 | char* regionName; 71 | char* modelName; 72 | CFGU_SecureInfoGetRegion(®ion); 73 | CFGU_GetSystemModel(&model); 74 | 75 | switch (region) { 76 | case 0: regionName = "JPN"; break; 77 | case 1: regionName = "NTSC"; break; 78 | case 2: 79 | case 3: regionName = "PAL"; break; // I implemented the australian case but really no one cares 80 | case 4: regionName = "CHN"; break; 81 | case 5: regionName = "KOR"; break; 82 | case 6: regionName = "TWN"; break; 83 | default: regionName = "UNKNOWN"; 84 | } 85 | 86 | switch (model) { 87 | case 0: modelName = "O3DS"; break; 88 | case 1: modelName = "O3DS XL"; break; 89 | case 2: modelName = "N3DS"; break; 90 | case 3: modelName = "2DS"; break; 91 | case 4: modelName = "N3DS XL"; break; 92 | default: modelName = "UNKNOWN"; 93 | } 94 | 95 | bool isNew = (model == 2 || model == 4); 96 | 97 | canContinue = false; 98 | 99 | /*Handle packagesDir; 100 | //FS_Archive fsarchive; 101 | FS_DirectoryEntry* entries; 102 | u32 actualAmount = 0; 103 | u8 currentPack; 104 | bool showNot; 105 | FS_DirectoryEntry chosenPack; 106 | 107 | packChoice: ; // despite common belief, gotoes are great when you're not doing the fuck with the memory 108 | FS_Archive fsarchive = {ARCHIVE_SDMC, {PATH_EMPTY, 0, 0}}; 109 | FSUSER_OpenArchive(&fsarchive); 110 | res = FSUSER_OpenDirectory(&packagesDir, fsarchive, fsMakePath(PATH_ASCII, "/downgrade")); 111 | FSUSER_CloseArchive(&fsarchive); 112 | 113 | //I have no idea if this works correctly, apparently you can't set it on the same line, pointers when referencing are redundant 114 | entries = malloc(16 * sizeof(FS_DirectoryEntry)); 115 | 116 | res = FSDIR_Read(packagesDir, &actualAmount, 16, entries); 117 | if (actualAmount == 0) { 118 | consoleClear(); 119 | clearScreens(); 120 | 121 | printf("No file found.\n\nPress (B) to exit.\n\n%x", res); 122 | while (aptMainLoop() && !canContinue) { 123 | hidScanInput(); 124 | kDown = hidKeysDown(); 125 | if (kDown & KEY_B) { 126 | free(entries); 127 | FSDIR_Close(packagesDir); 128 | return 1; 129 | } 130 | 131 | gspWaitForVBlank(); 132 | gfxFlushBuffers(); 133 | gfxSwapBuffers(); 134 | } 135 | } 136 | 137 | currentPack = 0; 138 | showNot = false; 139 | shouldNotChange = true; 140 | while (aptMainLoop() && !canContinue) { 141 | consoleClear(); 142 | clearScreens(); 143 | 144 | printf("Please choose the downgrade pack\nyou want to install.\n\n"); 145 | 146 | printf(" < %s >\n", entries[currentPack].shortName); 147 | 148 | printf("%s\nUse (LEFT) and (RIGHT) to choose.\nPress (X) to confirm.", (showNot ? "Not a Time Traveller Package!\n" : "")); 149 | 150 | //printf("\n\n%i\n%i\n%i\n%i", entries[currentPack].shortExt[0], entries[currentPack].shortExt[1] ,entries[currentPack].shortExt[2], entries[currentPack].shortExt[3]); 151 | 152 | while (aptMainLoop() && !canContinue && shouldNotChange) { 153 | hidScanInput(); 154 | kDown = hidKeysDown(); 155 | if (kDown & KEY_B) { 156 | free(entries); 157 | return 1; 158 | } 159 | 160 | if (kDown & KEY_LEFT) { 161 | showNot = false; 162 | shouldNotChange = false; 163 | if (currentPack == 0) currentPack = actualAmount-1; 164 | else currentPack--; 165 | } else if (kDown & KEY_RIGHT) { 166 | showNot = false; 167 | shouldNotChange = false; 168 | if (currentPack == actualAmount-1) currentPack = 0; 169 | else currentPack++; 170 | } else if (kDown & KEY_X) { 171 | shouldNotChange = false; 172 | if (entries[currentPack].shortExt[0] != 84 || entries[currentPack].shortExt[1] != 84 || entries[currentPack].shortExt[2] != 80 || entries[currentPack].shortExt[3] != 0) 173 | showNot = true; // shortExt != "TTP" 174 | else canContinue = true; 175 | } 176 | 177 | 178 | gspWaitForVBlank(); 179 | gfxFlushBuffers(); 180 | gfxSwapBuffers(); 181 | } 182 | shouldNotChange = true; 183 | } 184 | 185 | chosenPack = entries[currentPack]; 186 | FSDIR_Close(packagesDir); 187 | free(entries);*/ 188 | 189 | canContinue = false; 190 | timer = 0; 191 | 192 | consoleClear(); 193 | clearScreens(); 194 | 195 | printf("Detected model: %s ", modelName); 196 | printf("(%s family)\n", isNew ? "New3DS" : "Old3DS"); 197 | printf("Detected region: %s\n", regionName); 198 | //printf("Detected firmware: %i.%i.%i\n", major, minor, rev); 199 | printf("Downgrade pack: %s\n\n", /*chosenPack.shortName*/"/downgrade.ttp"); 200 | 201 | bool canGoAhead = false; 202 | if (strcmp(regionName, "UNKNOWN") == 0) { 203 | printf("Woops! Something weird happened with the region.\nREGIONID: %i\n", region); 204 | printf("Please contact the community for more info.\n\n"); 205 | } else { 206 | if ((region == 5 || region == 6) && isNew) { 207 | printf("Sorry, we didn't know there were N3DS in your region.\nREGIONID: %i\n", region); 208 | printf("Please contact the community for more info.\n\n"); 209 | } else { 210 | if (strcmp(modelName, "UNKNOWN") == 0) { 211 | printf("Woops! Something weird happened with the model.\nMODELID: %i\n", model); 212 | printf("Please contact the community for more info.\n\n"); 213 | } else { 214 | printf("Is that correct?\n"); 215 | printf("In case of error, please exit and contact the community\nfor more information. DO NOT try if there is\nat least one info wrong.\n\n"); 216 | if (timer == 0) { 217 | printf("Press (A) to confirm.\n"); 218 | canGoAhead = true; 219 | } 220 | } 221 | } 222 | } 223 | 224 | //printf("Press (LEFT) to choose another downgrade pack.\n"); 225 | printf("Press (B) to exit."); 226 | 227 | while (aptMainLoop() && !canContinue) { 228 | hidScanInput(); 229 | kDown = hidKeysDown(); 230 | if (kDown & KEY_B) 231 | return 1; 232 | 233 | if (kDown & KEY_A && canGoAhead) 234 | canContinue = true; 235 | 236 | //if (kDown & KEY_LEFT) 237 | // goto packChoice; 238 | 239 | gspWaitForVBlank(); 240 | gfxFlushBuffers(); 241 | gfxSwapBuffers(); 242 | } 243 | 244 | if (!canContinue) return 0; 245 | consoleClear(); 246 | clearScreens(); 247 | printf("Verifying your downgrade pack...\nThis can take a minute."); 248 | 249 | //char* completePath = malloc(strlen(chosenPack.shortName) + 11); 250 | //strcpy(completePath, "/downgrade/"); 251 | 252 | /*char* asciiName = malloc(0x106); 253 | u32 i; 254 | for (i = 0; chosenPack.name[i] != NULL; i++) { 255 | if (chosenPack.name[i] < 128) { 256 | strcat(asciiName, &(chosenPack.name[i])); 257 | } 258 | } 259 | 260 | strcat(completePath, asciiName);*/ 261 | char* completePath = "/downgrade.ttp"; 262 | //free(asciiName); 263 | if (!checkTTP(region, isNew, completePath)) { 264 | consoleClear(); 265 | clearScreens(); 266 | printf("Your downgrade pack (or KTM itself)\nseems corrupted or inappropriate.\n"); 267 | printf("Press (B) to exit."); 268 | while (aptMainLoop()) { 269 | hidScanInput(); 270 | kDown = hidKeysDown(); 271 | if (kDown & KEY_B) 272 | return 1; 273 | 274 | gspWaitForVBlank(); 275 | gfxFlushBuffers(); 276 | gfxSwapBuffers(); 277 | } 278 | return 0; 279 | } 280 | 281 | u8 isBatteryCharging; 282 | u8 batteryLevel; 283 | u8 latestCharging = 0; 284 | u8 latestLevel = 0; 285 | 286 | canContinue = false; 287 | 288 | shouldNotChange = true; 289 | 290 | while (aptMainLoop() && !canContinue) { 291 | consoleClear(); 292 | clearScreens(); 293 | 294 | PTMU_GetBatteryChargeState(&isBatteryCharging); 295 | PTMU_GetBatteryLevel(&batteryLevel); 296 | 297 | printf("Please leave your console charging during the process.\n\n"); 298 | 299 | if (isBatteryCharging == 0) { 300 | printf("Your console is not charging. Please leave it charging.\n\n"); 301 | } else { 302 | if (batteryLevel >= 3) { 303 | printf("Your console is now ready for the downgrade process.\n\n"); 304 | printf("AFTER THAT POINT YOU MUST NOT TURN OFF THE CONSOLE OR REMOVE\nTHE SD CARD OR IT WILL BRICK!\n\n"); 305 | printf("Press (A) to proceed.\n"); 306 | } else { 307 | printf("To be extra sure, please leave it charging a bit.\n"); 308 | printf("Current charging level: %i of 3 needed\n\n", batteryLevel); 309 | } 310 | } 311 | 312 | printf("Press (B) to exit."); 313 | 314 | while (aptMainLoop() && !canContinue && shouldNotChange) { 315 | 316 | hidScanInput(); 317 | kDown = hidKeysDown(); 318 | 319 | PTMU_GetBatteryChargeState(&isBatteryCharging); 320 | PTMU_GetBatteryLevel(&batteryLevel); 321 | 322 | if (kDown & KEY_B) 323 | return 1; 324 | 325 | if (batteryLevel >= 3 && isBatteryCharging != 0 && kDown & KEY_A) 326 | canContinue = true; 327 | 328 | if (batteryLevel != latestLevel) { 329 | shouldNotChange = false; 330 | latestLevel = batteryLevel; 331 | } 332 | 333 | if (isBatteryCharging != latestCharging) { 334 | shouldNotChange = false; 335 | latestCharging = isBatteryCharging; 336 | } 337 | 338 | } 339 | } 340 | 341 | if (!canContinue) return 0; 342 | 343 | // POINT OF NO RETURN 344 | 345 | u32 *threadStack = memalign(32, 4 * 1024); 346 | 347 | threadPath = completePath; 348 | threadMediatype = MEDIATYPE_NAND; 349 | threadSafeMode = safeMode; 350 | isDone = false; 351 | 352 | consoleClear(); 353 | printf("DOWNGRADE PROCESS HAS STARTED. FOR YOUR OWN SAFETY:\n\n"); 354 | printf("DO NOT panic, this won't take long.\n"); 355 | printf("DO NOT turn off you console during\nthe process: it WILL brick.\n"); 356 | printf("DO NOT get to HomebrewMenu during\nthe process: it WILL brick.\n"); 357 | printf("DO NOT remove the SD card during\nthe process: it WILL brick.\n"); 358 | printf("DO NOT remove the battery during\nthe process: it WILL brick.\n"); 359 | printf("AVOID to unplug the charger.\n\n"); 360 | printf("Please wait..."); 361 | 362 | consoleInit(GFX_BOTTOM, &botConsole); 363 | consoleSelect(&botConsole); 364 | 365 | res = svcCreateThread(&threadInstallHandle, installTTPthread, 0, &threadStack[1024], 0x3f, 0); 366 | 367 | while (!isDone) { 368 | gspWaitForVBlank(); 369 | gfxFlushBuffers(); // Placeholder for future animation 370 | gfxSwapBuffers(); 371 | } 372 | 373 | consoleClear(); 374 | consoleSelect(&topConsole); 375 | 376 | printf("%sowngrade complete.\nPress (START) to reboot the console.", (safeMode ? "SAFE_MODE d" : "D")); 377 | 378 | while (aptMainLoop()) { 379 | 380 | gspWaitForVBlank(); 381 | gfxFlushBuffers(); 382 | gfxSwapBuffers(); 383 | 384 | hidScanInput(); 385 | kDown = hidKeysDown(); 386 | if (kDown & KEY_START) { 387 | aptOpenSession(); 388 | APT_HardwareResetAsync(); 389 | aptCloseSession(); 390 | return 0; 391 | } 392 | 393 | } 394 | 395 | return 0; 396 | } 397 | 398 | u8 mainMenu() { 399 | u32 kDown = 0; 400 | // shouldNotChange = true; 401 | gspWaitForVBlank(); 402 | consoleClear(); 403 | //clearScreens(); 404 | printf("KernelTimeMachine\nFix your mistakes\n"); 405 | printf("-----------------\n\n"); 406 | printf("(A) Install CIA [WIP]\n"); 407 | printf("(Y) Downgrade Firmware\n"); 408 | printf("(X) Downgrade SAFE_MODE firm\n"); 409 | printf("(L+Y) Downgrade MSET [WIP]\n"); 410 | printf("(R+Y) Downgrade Browser [WIP]\n"); 411 | printf("(START) Exit"); 412 | //gfxFlushBuffers(); 413 | //gfxSwapBuffers(); 414 | while (aptMainLoop()) { 415 | hidScanInput(); 416 | kDown = hidKeysDown(); 417 | if (kDown & KEY_START) 418 | return 0; 419 | if (kDown & KEY_Y) 420 | { 421 | if (kDown & KEY_L) 422 | return 4; 423 | else if (kDown & KEY_R) 424 | return 5; 425 | else 426 | return 3; 427 | } 428 | if (kDown & KEY_X) 429 | return 6; 430 | } 431 | return 0; 432 | } 433 | -------------------------------------------------------------------------------- /source/menu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // KernelTimeMachine 3 | // Safe CIA manager 4 | // Licensed under GNU General Public License (GPL) 5 | // Check out https://www.gnu.org/licenses/gpl.html 6 | 7 | u8 mainMenu(); 8 | u8 downgradeMenu(bool safeMode); 9 | 10 | extern PrintConsole topConsole; 11 | extern PrintConsole botConsole; 12 | -------------------------------------------------------------------------------- /source/sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FIPS-180-1 compliant SHA-1 implementation 3 | * 4 | * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 5 | * SPDX-License-Identifier: Apache-2.0 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 8 | * not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * This file is part of mbed TLS (https://tls.mbed.org) 20 | */ 21 | // Modifications were made. 22 | /* 23 | * The SHA-1 standard was published by NIST in 1993. 24 | * 25 | * http://www.itl.nist.gov/fipspubs/fip180-1.htm 26 | */ 27 | 28 | #include "sha1.h" 29 | 30 | #include 31 | #include 32 | #include 33 | #include <3ds.h> 34 | 35 | /* Implementation that should never be optimized out by the compiler */ 36 | static void mbedtls_zeroize( void *v, __SIZE_TYPE__ n ) { 37 | volatile unsigned char *p = v; while( n-- ) *p++ = 0; 38 | } 39 | 40 | /* 41 | * 32-bit integer manipulation macros (big endian) 42 | */ 43 | #ifndef GET_UINT32_BE 44 | #define GET_UINT32_BE(n,b,i) \ 45 | { \ 46 | (n) = ( (u32) (b)[(i) ] << 24 ) \ 47 | | ( (u32) (b)[(i) + 1] << 16 ) \ 48 | | ( (u32) (b)[(i) + 2] << 8 ) \ 49 | | ( (u32) (b)[(i) + 3] ); \ 50 | } 51 | #endif 52 | 53 | #ifndef PUT_UINT32_BE 54 | #define PUT_UINT32_BE(n,b,i) \ 55 | { \ 56 | (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ 57 | (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ 58 | (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ 59 | (b)[(i) + 3] = (unsigned char) ( (n) ); \ 60 | } 61 | #endif 62 | 63 | void mbedtls_sha1_init( mbedtls_sha1_context *ctx ) 64 | { 65 | memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); 66 | } 67 | 68 | void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) 69 | { 70 | if( ctx == NULL ) 71 | return; 72 | 73 | mbedtls_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); 74 | } 75 | 76 | void mbedtls_sha1_clone( mbedtls_sha1_context *dst, 77 | const mbedtls_sha1_context *src ) 78 | { 79 | *dst = *src; 80 | } 81 | 82 | /* 83 | * SHA-1 context setup 84 | */ 85 | void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ) 86 | { 87 | ctx->total[0] = 0; 88 | ctx->total[1] = 0; 89 | 90 | ctx->state[0] = 0x67452301; 91 | ctx->state[1] = 0xEFCDAB89; 92 | ctx->state[2] = 0x98BADCFE; 93 | ctx->state[3] = 0x10325476; 94 | ctx->state[4] = 0xC3D2E1F0; 95 | } 96 | 97 | #if !defined(MBEDTLS_SHA1_PROCESS_ALT) 98 | void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ) 99 | { 100 | u32 temp, W[16], A, B, C, D, E; 101 | 102 | GET_UINT32_BE( W[ 0], data, 0 ); 103 | GET_UINT32_BE( W[ 1], data, 4 ); 104 | GET_UINT32_BE( W[ 2], data, 8 ); 105 | GET_UINT32_BE( W[ 3], data, 12 ); 106 | GET_UINT32_BE( W[ 4], data, 16 ); 107 | GET_UINT32_BE( W[ 5], data, 20 ); 108 | GET_UINT32_BE( W[ 6], data, 24 ); 109 | GET_UINT32_BE( W[ 7], data, 28 ); 110 | GET_UINT32_BE( W[ 8], data, 32 ); 111 | GET_UINT32_BE( W[ 9], data, 36 ); 112 | GET_UINT32_BE( W[10], data, 40 ); 113 | GET_UINT32_BE( W[11], data, 44 ); 114 | GET_UINT32_BE( W[12], data, 48 ); 115 | GET_UINT32_BE( W[13], data, 52 ); 116 | GET_UINT32_BE( W[14], data, 56 ); 117 | GET_UINT32_BE( W[15], data, 60 ); 118 | 119 | #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) 120 | 121 | #define R(t) \ 122 | ( \ 123 | temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \ 124 | W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \ 125 | ( W[t & 0x0F] = S(temp,1) ) \ 126 | ) 127 | 128 | #define P(a,b,c,d,e,x) \ 129 | { \ 130 | e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ 131 | } 132 | 133 | A = ctx->state[0]; 134 | B = ctx->state[1]; 135 | C = ctx->state[2]; 136 | D = ctx->state[3]; 137 | E = ctx->state[4]; 138 | 139 | #define F(x,y,z) (z ^ (x & (y ^ z))) 140 | #define K 0x5A827999 141 | 142 | P( A, B, C, D, E, W[0] ); 143 | P( E, A, B, C, D, W[1] ); 144 | P( D, E, A, B, C, W[2] ); 145 | P( C, D, E, A, B, W[3] ); 146 | P( B, C, D, E, A, W[4] ); 147 | P( A, B, C, D, E, W[5] ); 148 | P( E, A, B, C, D, W[6] ); 149 | P( D, E, A, B, C, W[7] ); 150 | P( C, D, E, A, B, W[8] ); 151 | P( B, C, D, E, A, W[9] ); 152 | P( A, B, C, D, E, W[10] ); 153 | P( E, A, B, C, D, W[11] ); 154 | P( D, E, A, B, C, W[12] ); 155 | P( C, D, E, A, B, W[13] ); 156 | P( B, C, D, E, A, W[14] ); 157 | P( A, B, C, D, E, W[15] ); 158 | P( E, A, B, C, D, R(16) ); 159 | P( D, E, A, B, C, R(17) ); 160 | P( C, D, E, A, B, R(18) ); 161 | P( B, C, D, E, A, R(19) ); 162 | 163 | #undef K 164 | #undef F 165 | 166 | #define F(x,y,z) (x ^ y ^ z) 167 | #define K 0x6ED9EBA1 168 | 169 | P( A, B, C, D, E, R(20) ); 170 | P( E, A, B, C, D, R(21) ); 171 | P( D, E, A, B, C, R(22) ); 172 | P( C, D, E, A, B, R(23) ); 173 | P( B, C, D, E, A, R(24) ); 174 | P( A, B, C, D, E, R(25) ); 175 | P( E, A, B, C, D, R(26) ); 176 | P( D, E, A, B, C, R(27) ); 177 | P( C, D, E, A, B, R(28) ); 178 | P( B, C, D, E, A, R(29) ); 179 | P( A, B, C, D, E, R(30) ); 180 | P( E, A, B, C, D, R(31) ); 181 | P( D, E, A, B, C, R(32) ); 182 | P( C, D, E, A, B, R(33) ); 183 | P( B, C, D, E, A, R(34) ); 184 | P( A, B, C, D, E, R(35) ); 185 | P( E, A, B, C, D, R(36) ); 186 | P( D, E, A, B, C, R(37) ); 187 | P( C, D, E, A, B, R(38) ); 188 | P( B, C, D, E, A, R(39) ); 189 | 190 | #undef K 191 | #undef F 192 | 193 | #define F(x,y,z) ((x & y) | (z & (x | y))) 194 | #define K 0x8F1BBCDC 195 | 196 | P( A, B, C, D, E, R(40) ); 197 | P( E, A, B, C, D, R(41) ); 198 | P( D, E, A, B, C, R(42) ); 199 | P( C, D, E, A, B, R(43) ); 200 | P( B, C, D, E, A, R(44) ); 201 | P( A, B, C, D, E, R(45) ); 202 | P( E, A, B, C, D, R(46) ); 203 | P( D, E, A, B, C, R(47) ); 204 | P( C, D, E, A, B, R(48) ); 205 | P( B, C, D, E, A, R(49) ); 206 | P( A, B, C, D, E, R(50) ); 207 | P( E, A, B, C, D, R(51) ); 208 | P( D, E, A, B, C, R(52) ); 209 | P( C, D, E, A, B, R(53) ); 210 | P( B, C, D, E, A, R(54) ); 211 | P( A, B, C, D, E, R(55) ); 212 | P( E, A, B, C, D, R(56) ); 213 | P( D, E, A, B, C, R(57) ); 214 | P( C, D, E, A, B, R(58) ); 215 | P( B, C, D, E, A, R(59) ); 216 | 217 | #undef K 218 | #undef F 219 | 220 | #define F(x,y,z) (x ^ y ^ z) 221 | #define K 0xCA62C1D6 222 | 223 | P( A, B, C, D, E, R(60) ); 224 | P( E, A, B, C, D, R(61) ); 225 | P( D, E, A, B, C, R(62) ); 226 | P( C, D, E, A, B, R(63) ); 227 | P( B, C, D, E, A, R(64) ); 228 | P( A, B, C, D, E, R(65) ); 229 | P( E, A, B, C, D, R(66) ); 230 | P( D, E, A, B, C, R(67) ); 231 | P( C, D, E, A, B, R(68) ); 232 | P( B, C, D, E, A, R(69) ); 233 | P( A, B, C, D, E, R(70) ); 234 | P( E, A, B, C, D, R(71) ); 235 | P( D, E, A, B, C, R(72) ); 236 | P( C, D, E, A, B, R(73) ); 237 | P( B, C, D, E, A, R(74) ); 238 | P( A, B, C, D, E, R(75) ); 239 | P( E, A, B, C, D, R(76) ); 240 | P( D, E, A, B, C, R(77) ); 241 | P( C, D, E, A, B, R(78) ); 242 | P( B, C, D, E, A, R(79) ); 243 | 244 | #undef K 245 | #undef F 246 | 247 | ctx->state[0] += A; 248 | ctx->state[1] += B; 249 | ctx->state[2] += C; 250 | ctx->state[3] += D; 251 | ctx->state[4] += E; 252 | } 253 | #endif /* !MBEDTLS_SHA1_PROCESS_ALT */ 254 | 255 | /* 256 | * SHA-1 process buffer 257 | */ 258 | void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, __SIZE_TYPE__ ilen ) 259 | { 260 | __SIZE_TYPE__ fill; 261 | u32 left; 262 | 263 | if( ilen == 0 ) 264 | return; 265 | 266 | left = ctx->total[0] & 0x3F; 267 | fill = 64 - left; 268 | 269 | ctx->total[0] += (u32) ilen; 270 | ctx->total[0] &= 0xFFFFFFFF; 271 | 272 | if( ctx->total[0] < (u32) ilen ) 273 | ctx->total[1]++; 274 | 275 | if( left && ilen >= fill ) 276 | { 277 | memcpy( (void *) (ctx->buffer + left), input, fill ); 278 | mbedtls_sha1_process( ctx, ctx->buffer ); 279 | input += fill; 280 | ilen -= fill; 281 | left = 0; 282 | } 283 | 284 | while( ilen >= 64 ) 285 | { 286 | mbedtls_sha1_process( ctx, input ); 287 | input += 64; 288 | ilen -= 64; 289 | } 290 | 291 | if( ilen > 0 ) 292 | memcpy( (void *) (ctx->buffer + left), input, ilen ); 293 | } 294 | 295 | static const unsigned char sha1_padding[64] = 296 | { 297 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 298 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 299 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 300 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 301 | }; 302 | 303 | /* 304 | * SHA-1 final digest 305 | */ 306 | void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ) 307 | { 308 | u32 last, padn; 309 | u32 high, low; 310 | unsigned char msglen[8]; 311 | 312 | high = ( ctx->total[0] >> 29 ) 313 | | ( ctx->total[1] << 3 ); 314 | low = ( ctx->total[0] << 3 ); 315 | 316 | PUT_UINT32_BE( high, msglen, 0 ); 317 | PUT_UINT32_BE( low, msglen, 4 ); 318 | 319 | last = ctx->total[0] & 0x3F; 320 | padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); 321 | 322 | mbedtls_sha1_update( ctx, sha1_padding, padn ); 323 | mbedtls_sha1_update( ctx, msglen, 8 ); 324 | 325 | PUT_UINT32_BE( ctx->state[0], output, 0 ); 326 | PUT_UINT32_BE( ctx->state[1], output, 4 ); 327 | PUT_UINT32_BE( ctx->state[2], output, 8 ); 328 | PUT_UINT32_BE( ctx->state[3], output, 12 ); 329 | PUT_UINT32_BE( ctx->state[4], output, 16 ); 330 | } 331 | 332 | /* 333 | * output = SHA-1( input buffer ) 334 | */ 335 | void mbedtls_sha1( const unsigned char *input, __SIZE_TYPE__ ilen, unsigned char output[20] ) 336 | { 337 | mbedtls_sha1_context ctx; 338 | 339 | mbedtls_sha1_init( &ctx ); 340 | mbedtls_sha1_starts( &ctx ); 341 | mbedtls_sha1_update( &ctx, input, ilen ); 342 | mbedtls_sha1_finish( &ctx, output ); 343 | mbedtls_sha1_free( &ctx ); 344 | } 345 | -------------------------------------------------------------------------------- /source/sha1.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /** 3 | * \file mbedtls_sha1.h 4 | * 5 | * \brief SHA-1 cryptographic hash function 6 | * 7 | * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 8 | * SPDX-License-Identifier: Apache-2.0 9 | * 10 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 11 | * not use this file except in compliance with the License. 12 | * You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, software 17 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 18 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | * See the License for the specific language governing permissions and 20 | * limitations under the License. 21 | * 22 | * This file is part of mbed TLS (https://tls.mbed.org) 23 | */ 24 | // Modifications were made. 25 | /** 26 | * \brief SHA-1 context structure 27 | */ 28 | 29 | #include <3ds.h> 30 | 31 | typedef struct 32 | { 33 | u32 total[2]; /*!< number of bytes processed */ 34 | u32 state[5]; /*!< intermediate digest state */ 35 | unsigned char buffer[64]; /*!< data block being processed */ 36 | } 37 | mbedtls_sha1_context; 38 | 39 | /** 40 | * \brief Initialize SHA-1 context 41 | * 42 | * \param ctx SHA-1 context to be initialized 43 | */ 44 | void mbedtls_sha1_init( mbedtls_sha1_context *ctx ); 45 | 46 | /** 47 | * \brief Clear SHA-1 context 48 | * 49 | * \param ctx SHA-1 context to be cleared 50 | */ 51 | void mbedtls_sha1_free( mbedtls_sha1_context *ctx ); 52 | 53 | /** 54 | * \brief Clone (the state of) a SHA-1 context 55 | * 56 | * \param dst The destination context 57 | * \param src The context to be cloned 58 | */ 59 | void mbedtls_sha1_clone( mbedtls_sha1_context *dst, 60 | const mbedtls_sha1_context *src ); 61 | 62 | /** 63 | * \brief SHA-1 context setup 64 | * 65 | * \param ctx context to be initialized 66 | */ 67 | void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ); 68 | 69 | /** 70 | * \brief SHA-1 process buffer 71 | * 72 | * \param ctx SHA-1 context 73 | * \param input buffer holding the data 74 | * \param ilen length of the input data 75 | */ 76 | void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, __SIZE_TYPE__ ilen ); 77 | 78 | /** 79 | * \brief SHA-1 final digest 80 | * 81 | * \param ctx SHA-1 context 82 | * \param output SHA-1 checksum result 83 | */ 84 | void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ); 85 | 86 | /* Internal use */ 87 | void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ); -------------------------------------------------------------------------------- /source/ttp.c: -------------------------------------------------------------------------------- 1 | #include <3ds.h> 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "archives.h" 7 | #include "sha1.h" 8 | #include "ttp.h" 9 | #include "cia.h" 10 | 11 | // KernelTimeMachine 12 | // Safe CIA manager 13 | // Licensed under GNU General Public License (GPL) 14 | // Check out https://www.gnu.org/licenses/gpl.html 15 | 16 | #define USELESS92AMOUNT (12) 17 | u64 uselessTitlesFor92[USELESS92AMOUNT] = { // Latest update: 10.3 18 | 19 | 0x0004001B00019002, 0x000400300000B902, 0x0004013000004002, 0x0004003000009502, 0x0004003000009E02, 0x0004001B00010802, 20 | 0x0004009B00010402, 0x0004013000001A02, 0x0004013000001B02, 0x0004800542383841, 0x00048005484E4441, 0x0004800F484E4841 21 | 22 | }; 23 | 24 | bool checkTTP(char region, bool isNew, char* path) { // Verifies the integrity of a TTP file and if it corresponds to the console. (needs sha1.c) 25 | 26 | mbedtls_sha1_context context; 27 | 28 | // Just figured out there's a cleaner syntax to perform sdmc reads. Note to future. 29 | 30 | Result res; 31 | Handle file; 32 | FS_Archive archive = {ARCHIVE_SDMC, {PATH_EMPTY, 0, 0}}; 33 | FSUSER_OpenArchive(&archive); 34 | res = FSUSER_OpenFile(&file, archive, fsMakePath(PATH_ASCII, path), FS_OPEN_READ, 0); 35 | FSUSER_CloseArchive(&archive); 36 | 37 | if (res) 38 | { 39 | FSFILE_Close(file); 40 | return false; 41 | } 42 | 43 | u32 bytesRead = 0; 44 | char* buf = malloc(0x3); 45 | FSFILE_Read(file, &bytesRead, 0x0, buf, 0x3); 46 | if ((u8)buf[0] != 0x74 || (u8)buf[1] != 0x74 || (u8)buf[2] != 0x70) { free(buf); return false; } // if (buf != "ttp") 47 | free(buf); // not sure if freeing all the time is needed, maybe allocating 0x14 since the beginning should be enough 48 | 49 | buf = malloc(0x1); 50 | FSFILE_Read(file, &bytesRead, 0x3, buf, 0x1); 51 | if ((u8)buf[0] != region && (u8)buf[0] != 0xFF) { free(buf); return false; } 52 | //free(buf); 53 | 54 | //buf = malloc(0x1); 55 | FSFILE_Read(file, &bytesRead, 0x4, buf, 0x1); 56 | if ((u8)buf[0] != (u8)isNew && (u8)buf[0] != 0xFF) { free(buf); return false; } 57 | free(buf); 58 | 59 | // SHA-1 check 60 | buf = malloc(0x14); 61 | FSFILE_Read(file, &bytesRead, 0x5, buf, 0x14); 62 | mbedtls_sha1_init(&context); 63 | mbedtls_sha1_starts(&context); 64 | 65 | char t[4]; 66 | FSFILE_Read(file, &bytesRead, 0x19, t, 4); // t is an array, so it's a pointer here 67 | u32 ulSize = 68 | ( ((u32)t[0]) << (8*3) ) | // t[0] stores MSB of UInt32 69 | ( ((u32)t[1]) << (8*2) ) | // .. 70 | ( ((u32)t[2]) << (8*1) ) | // .. 71 | ( ((u32)t[3]) << (8*0) ) ; // t[3] stores LSB of UInt32 72 | 73 | u32 blockAmount = ulSize / 0x160000; 74 | u32 i; 75 | u8* block = malloc(0x160000); 76 | for (i = 0; i < blockAmount; i++) { 77 | FSFILE_Read(file, &bytesRead, 0x1D+0x160000*i, block, 0x160000); 78 | mbedtls_sha1_update(&context, block, 0x160000); 79 | } 80 | 81 | if (ulSize % 0x160000 != 0) { 82 | FSFILE_Read(file, &bytesRead, 0x1D+0x160000*blockAmount, block, ulSize-0x160000*blockAmount); 83 | mbedtls_sha1_update(&context, block, bytesRead); 84 | } 85 | 86 | free(block); 87 | 88 | FSFILE_Close(file); 89 | //FSUSER_CloseArchive(&archive); 90 | 91 | u8 hash[20]; 92 | mbedtls_sha1_finish(&context, hash); 93 | 94 | //shaBytes.c = buf; 95 | 96 | 97 | for (i = 0; i < 20; i++) { 98 | if (hash[i] != buf[i]) { free(buf); return false; } 99 | } 100 | 101 | free(buf); 102 | return true; 103 | 104 | } 105 | 106 | void removeUselessTitles(u8 mediatype) { 107 | 108 | printf("Removing useless titles...\n"); 109 | u32 i; 110 | for (i = 0; i < USELESS92AMOUNT; i++) { 111 | if (checkIfInstalled(mediatype, uselessTitlesFor92[i])) { 112 | if (uselessTitlesFor92[i] >> 32 & 0xFFFF) AM_DeleteTitle(mediatype, uselessTitlesFor92[i]); 113 | else AM_DeleteAppTitle(mediatype, uselessTitlesFor92[i]); 114 | } 115 | } 116 | 117 | } 118 | 119 | bool installTTP(char* path, u8 mediatype, bool safeMode) { // Install a TTP file. (needs libzip and installCIA) 120 | 121 | Result res; 122 | FS_Archive archive = {ARCHIVE_SDMC, {PATH_EMPTY, 0, 0}}; 123 | FSUSER_OpenArchive(&archive); 124 | FSUSER_DeleteDirectoryRecursively(archive, fsMakePath(PATH_ASCII, "/tmp/cias")); 125 | FSUSER_CreateDirectory(archive, fsMakePath(PATH_ASCII, "/tmp/cias"), 0); 126 | FILE* ttp = fopen(path, "rb"); 127 | FILE* tmp = fopen("/tmp/cias/ttp.tmp", "wb"); 128 | 129 | u32 size; 130 | fseek(ttp, 0x19, SEEK_SET); 131 | fread(&size, 0x4, 1, ttp); 132 | fseek(ttp, 0x1D, SEEK_SET); 133 | 134 | u32 blockAmount = size / 0x160000; // Finds how many blocks of 4MB you have in the file 135 | u32 i; 136 | char* block = malloc(0x160000); 137 | for (i = 0; i < blockAmount; i++) { 138 | fread(block, 1, 0x160000, ttp); 139 | fwrite(block, 1, 0x160000, tmp); 140 | } 141 | 142 | if (size % 0x160000 != 0) { 143 | fread(block, 1, size-0x160000*blockAmount, ttp); 144 | fwrite(block, 1, size-0x160000*blockAmount, tmp); 145 | } 146 | 147 | free(block); 148 | 149 | fclose(ttp); 150 | fclose(tmp); 151 | 152 | FSUSER_DeleteDirectoryRecursively(archive, fsMakePath(PATH_ASCII, "/tmp/cias")); 153 | FSUSER_CreateDirectory(archive, fsMakePath(PATH_ASCII, "/tmp/cias"), 0); 154 | 155 | Zip *zipHandle = ZipOpen("/tmp/cias/ttp.tmp"); 156 | ZipExtract(zipHandle, NULL); 157 | ZipClose(zipHandle); 158 | 159 | Handle ciaDir; 160 | FS_Archive fsarchive; 161 | u32 actualAmount; 162 | FS_DirectoryEntry* entries; 163 | 164 | FSUSER_DeleteFile(archive, fsMakePath(PATH_ASCII, "/tmp/cias/ttp.tmp")); 165 | res = FSUSER_OpenDirectory(&ciaDir, fsarchive, fsMakePath(PATH_ASCII, "/tmp/cias")); 166 | if (res != 0) { return false; } 167 | entries = malloc(256 * sizeof(FS_DirectoryEntry)); 168 | res = FSDIR_Read(ciaDir, &actualAmount, 256, entries); 169 | if (res != 0) { return false; } 170 | 171 | char* ciaPath; 172 | for (i = 0; i < actualAmount; i++) { 173 | ciaPath = malloc(14 + strlen(entries[i].shortName)); 174 | strcpy(ciaPath, "/tmp/cias/"); 175 | strcat(ciaPath, entries[i].shortName); 176 | strcat(ciaPath, ".cia"); 177 | 178 | // Tries to install the CIA 5 times before abandon 179 | for (u8 i = 0; i < 5 && !installCIA(ciaPath, mediatype, entries[i].shortName, safeMode); i++); 180 | 181 | free(ciaPath); 182 | } 183 | 184 | installPendingFIRM(); 185 | 186 | removeUselessTitles(mediatype); 187 | 188 | FSUSER_DeleteDirectoryRecursively(archive, fsMakePath(PATH_ASCII, "/tmp/cias")); 189 | 190 | FSUSER_CloseArchive(&archive); 191 | 192 | return true; 193 | 194 | } 195 | 196 | volatile char* threadPath; 197 | volatile u8 threadMediatype; 198 | volatile bool threadSafeMode; 199 | volatile bool isDone; 200 | Handle threadInstallHandle; 201 | 202 | void installTTPthread() { 203 | // TODO: Problem with (volatile char*) -> (char*) 204 | installTTP((char*) threadPath, threadMediatype, threadSafeMode); 205 | isDone = true; 206 | } 207 | -------------------------------------------------------------------------------- /source/ttp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // KernelTimeMachine 3 | // Safe CIA manager 4 | // Licensed under GNU General Public License (GPL) 5 | // Check out https://www.gnu.org/licenses/gpl.html 6 | 7 | void installTTPthread(); 8 | bool installTTP(char *path, u8 mediatype, bool safeMode); 9 | bool checkTTP(char region, bool isNew, char *path); 10 | void removeUselessTitles(u8 mediatype); 11 | 12 | extern Handle threadInstallHandle; 13 | extern volatile bool isDone; 14 | extern volatile u8 threadMediatype; 15 | extern volatile bool threadSafeMode; 16 | extern volatile char *threadPath; 17 | -------------------------------------------------------------------------------- /source/utils.c: -------------------------------------------------------------------------------- 1 | #include <3ds.h> 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // KernelTimeMachine 8 | // Safe CIA manager 9 | // Licensed under GNU General Public License (GPL) 10 | // Check out https://www.gnu.org/licenses/gpl.html 11 | 12 | u8* fbTopLeft; 13 | u8* fbTopRight; 14 | u8* fbBottom; 15 | 16 | void clearScreens() { 17 | memset(fbTopLeft, 0, 240 * 400 * 3); 18 | memset(fbTopRight, 0, 240 * 400 * 3); 19 | memset(fbBottom, 0, 240 * 320 * 3); 20 | } 21 | 22 | int error(char* msg, u8 errorCode) { 23 | consoleClear(); 24 | clearScreens(); 25 | printf("\n%s", msg); 26 | printf("\n\nPress (START) to exit."); 27 | u32 kDown; 28 | while (aptMainLoop()) { 29 | gspWaitForVBlank(); 30 | gfxFlushBuffers(); 31 | gfxSwapBuffers(); 32 | hidScanInput(); 33 | kDown = hidKeysDown(); 34 | if (kDown & KEY_START) 35 | break; 36 | } 37 | return errorCode; 38 | } 39 | -------------------------------------------------------------------------------- /source/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // KernelTimeMachine 3 | // Safe CIA manager 4 | // Licensed under GNU General Public License (GPL) 5 | // Check out https://www.gnu.org/licenses/gpl.html 6 | 7 | void clearScreens(); 8 | int error(char *msg, u8 errorCode); 9 | 10 | extern u8* fbTopLeft; 11 | extern u8* fbTopRight; 12 | extern u8* fbBottom; 13 | --------------------------------------------------------------------------------