mirror of
https://github.com/EchoStretch/kstuff.git
synced 2026-10-23 12:12:30 -05:00
253 lines
8.0 KiB
C
253 lines
8.0 KiB
C
#ifdef __WIN32__
|
|
#include <winsock2.h>
|
|
#include <windows.h>
|
|
#else
|
|
#define _GNU_SOURCE
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/select.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <inttypes.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#ifdef __WIN32__
|
|
typedef uint32_t in_addr_t;
|
|
typedef int socklen_t;
|
|
#define SHUT_WR SD_SEND
|
|
#define ERRNO WSAGetLastError()
|
|
#ifdef ECONNREFUSED
|
|
#undef ECONNREFUSED
|
|
#endif
|
|
#define ECONNREFUSED WSAECONNREFUSED
|
|
#define VAR_PREFIX "_"
|
|
|
|
ssize_t get_line(char** s, size_t* l, FILE* fin)
|
|
{
|
|
size_t i = 0;
|
|
int c;
|
|
while((c = fgetc(fin)) != '\n' && c != EOF)
|
|
{
|
|
while(i + 1 >= *l)
|
|
if(!*l)
|
|
*l = 1;
|
|
else
|
|
*l += *l;
|
|
*s = realloc(*s, *l);
|
|
s[0][i++] = c;
|
|
}
|
|
if(c == EOF && !feof(fin))
|
|
return -1;
|
|
s[0][i] = 0;
|
|
return i ? i : -1;
|
|
}
|
|
|
|
#else
|
|
#define SOCKET int
|
|
#define closesocket close
|
|
#define ERRNO errno
|
|
#define INVALID_SOCKET -1
|
|
#define system(...) do ; while(0)
|
|
#define VAR_PREFIX ""
|
|
#define get_line getline
|
|
#endif
|
|
|
|
asm(VAR_PREFIX"payload_data:\n.incbin \"payload.bin\"\n"VAR_PREFIX"payload_data_end:");
|
|
|
|
extern char payload_data[];
|
|
extern char payload_data_end[];
|
|
|
|
int main(int argc, const char** argv)
|
|
{
|
|
#ifdef __WIN32__
|
|
WSADATA wsd;
|
|
WSAStartup(0x202, &wsd);
|
|
#endif
|
|
if(argc < 2)
|
|
{
|
|
fprintf(stderr, "Must specify which PKG to install\n");
|
|
fprintf(stderr, "On Windows you can do so by dropping the .pkg \"into\" this program\n");
|
|
system("pause");
|
|
return 1;
|
|
}
|
|
in_addr_t ps4_ip = 0;
|
|
int interactive = 0;
|
|
if(argv[2])
|
|
ps4_ip = inet_addr(argv[2]);
|
|
else
|
|
{
|
|
printf("PS4 IP: ");
|
|
fflush(stdout);
|
|
char* ps4_ip_s = 0;
|
|
size_t ps4_ip_l = 0;
|
|
if(get_line(&ps4_ip_s, &ps4_ip_l, stdin) < 0)
|
|
{
|
|
free(ps4_ip_s);
|
|
return 1;
|
|
}
|
|
ps4_ip = inet_addr(ps4_ip_s);
|
|
free(ps4_ip_s);
|
|
interactive = 1;
|
|
}
|
|
#define fail(act, s) do { act; fprintf(stderr, " \r%s\n", s); if(interactive) system("pause"); return 1; } while(0)
|
|
if(ps4_ip == 0)
|
|
fail(, "Invalid IP address");
|
|
FILE* pkg = fopen(argv[1], "rb");
|
|
if(!pkg)
|
|
fail(, "Could not open PKG file");
|
|
SOCKET accept_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if(accept_sock == INVALID_SOCKET)
|
|
fail(fclose(pkg), "Could not create socket");
|
|
struct sockaddr_in bind_addr = {
|
|
.sin_family = AF_INET,
|
|
.sin_addr = {.s_addr = 0},
|
|
.sin_port = 0,
|
|
};
|
|
socklen_t sl = sizeof(bind_addr);
|
|
if(bind(accept_sock, (struct sockaddr*)&bind_addr, sizeof(bind_addr)))
|
|
fail(fclose(pkg); closesocket(accept_sock), "Could not assign local port");
|
|
if(getsockname(accept_sock, (struct sockaddr*)&bind_addr, &sl))
|
|
fail(fclose(pkg); closesocket(accept_sock), "Could not get local port");
|
|
if(listen(accept_sock, 1))
|
|
fail(fclose(pkg); closesocket(accept_sock), "Failed to put socket into listening mode");
|
|
struct sockaddr_in connect_addr = {
|
|
.sin_family = AF_INET,
|
|
.sin_addr = {.s_addr = ps4_ip},
|
|
.sin_port = 0,
|
|
};
|
|
int binloader_ports[3] = {9021, 9020, 9090};
|
|
SOCKET connect_sock;
|
|
for(int binloader_idx = 0; binloader_idx * sizeof(int) < sizeof(binloader_ports); binloader_idx++)
|
|
{
|
|
connect_addr.sin_port = htons(binloader_ports[binloader_idx]);
|
|
connect_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if(connect_sock == INVALID_SOCKET)
|
|
fail(closesocket(accept_sock), "Could not create socket");
|
|
printf("Trying to connect to port %d... ", binloader_ports[binloader_idx]);
|
|
if(!connect(connect_sock, (struct sockaddr*)&connect_addr, sizeof(connect_addr)))
|
|
{
|
|
printf("ok\n");
|
|
break;
|
|
}
|
|
printf("fail\n");
|
|
closesocket(connect_sock);
|
|
connect_sock = INVALID_SOCKET;
|
|
if(ERRNO != ECONNREFUSED)
|
|
fail(fclose(pkg); closesocket(accept_sock), "Could not connect to PS4");
|
|
}
|
|
if(connect_sock == INVALID_SOCKET)
|
|
fail(fclose(pkg); closesocket(accept_sock), "Could not connect to PS4");
|
|
if(getsockname(connect_sock, (struct sockaddr*)&connect_addr, &sl))
|
|
fail(fclose(pkg); closesocket(accept_sock); closesocket(connect_sock), "Could not get local address");
|
|
size_t sz = payload_data_end - payload_data;
|
|
char* p0 __attribute__((may_alias)) = malloc(sz);
|
|
char* p __attribute__((may_alias)) = p0;
|
|
if(!p)
|
|
fail(fclose(pkg); closesocket(accept_sock); closesocket(connect_sock), "Could not allocate memory for payload");
|
|
memcpy(p, payload_data, sz);
|
|
size_t nb3 = 0;
|
|
size_t b3_offset = sz;
|
|
struct {
|
|
uint32_t addr;
|
|
uint16_t port;
|
|
uint64_t pkg_size;
|
|
} __attribute__((packed,may_alias))* argument;
|
|
#ifdef __WIN32__
|
|
for(size_t i = 0; i < sz; i++)
|
|
{
|
|
if(p[i] == (char)0xb3)
|
|
nb3++;
|
|
else
|
|
nb3 = 0;
|
|
if(nb3 == 14)
|
|
{
|
|
b3_offset = i - 13;
|
|
break;
|
|
}
|
|
}
|
|
argument = (void*)(p + b3_offset);
|
|
#else
|
|
argument = memmem(p, sz, "\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3", 14);
|
|
#endif
|
|
argument->addr = connect_addr.sin_addr.s_addr;
|
|
argument->port = bind_addr.sin_port;
|
|
if(fseeko(pkg, 0, SEEK_END))
|
|
fail(fclose(pkg); closesocket(accept_sock); closesocket(connect_sock), "File is not seekable");
|
|
off_t file_size = argument->pkg_size = ftello(pkg);
|
|
if(file_size == (off_t)-1)
|
|
fail(fclose(pkg); closesocket(accept_sock); closesocket(connect_sock), "Could not determine file size");
|
|
fseek(pkg, 0, SEEK_SET);
|
|
while(sz > 0)
|
|
{
|
|
ssize_t chk = send(connect_sock, p, sz, 0);
|
|
if(chk <= 0)
|
|
fail(closesocket(accept_sock); closesocket(connect_sock), "Could not send payload");
|
|
p += chk;
|
|
sz -= chk;
|
|
}
|
|
closesocket(connect_sock);
|
|
free(p0);
|
|
SOCKET send_sock = accept(accept_sock, NULL, NULL);
|
|
if(send_sock == INVALID_SOCKET)
|
|
fail(fclose(pkg); closesocket(accept_sock), "Could not accept PKG request");
|
|
closesocket(accept_sock);
|
|
off_t total = 0;
|
|
char buf[4096], buf2[4096];
|
|
ssize_t chk = 0;
|
|
char* p2 = buf;
|
|
for(;;)
|
|
{
|
|
fd_set rd, wr;
|
|
FD_ZERO(&rd);
|
|
FD_SET(send_sock, &rd);
|
|
FD_ZERO(&wr);
|
|
FD_SET(send_sock, &wr);
|
|
if(select(send_sock + 1, &rd, &wr, NULL, NULL) <= 0)
|
|
fail(fclose(pkg); closesocket(send_sock), "select() failed");
|
|
if(FD_ISSET(send_sock, &rd))
|
|
{
|
|
if(recv(send_sock, buf2, sizeof(buf2), 0) <= 0)
|
|
fail(fclose(pkg); closesocket(send_sock), "Connection closed by PS4");
|
|
continue;
|
|
}
|
|
if(!FD_ISSET(send_sock, &wr))
|
|
continue;
|
|
if(chk == 0)
|
|
{
|
|
chk = fread(buf, 1, sizeof(buf), pkg);
|
|
if(chk < 0)
|
|
fail(fclose(pkg); closesocket(send_sock), "Failed to read from file");
|
|
if(chk == 0)
|
|
break;
|
|
p2 = buf;
|
|
}
|
|
ssize_t chk2 = send(send_sock, p2, chk, 0);
|
|
if(chk2 <= 0)
|
|
fail(fclose(pkg); closesocket(send_sock), "Failed to send data");
|
|
total += chk2;
|
|
p2 += chk2;
|
|
chk -= chk2;
|
|
fprintf(stderr, "%"PRIu64" of %"PRIu64" bytes transmitted (%.1f%%) \r", (uint64_t)total, (uint64_t)file_size, total * (double)100 / file_size);
|
|
fflush(stderr);
|
|
}
|
|
fclose(pkg);
|
|
//receive remaining acks
|
|
shutdown(send_sock, SHUT_WR);
|
|
while(recv(send_sock, buf2, sizeof(buf2), 0) > 0);
|
|
closesocket(send_sock);
|
|
if(total != file_size)
|
|
fail(, "Sanity check failed: transmitted size not equal to file size");
|
|
fprintf(stderr, " \rPKG transmitted successfully\n");
|
|
if(interactive)
|
|
system("pause");
|
|
return 0;
|
|
}
|