-
-
Save ddevault/c8a7404403d0499db01c248b944ba942 to your computer and use it in GitHub Desktop.
IOCCC 2018 entry
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <signal.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <sys/utsname.h> | |
#include <dirent.h> | |
#include <pwd.h> | |
#include <grp.h> | |
#define S "/>\x10v1" | |
#define F "8\x1E~\"\x1C" | |
#define O "HR&K\bS\x15\tMs|\7x\x1b" | |
struct passwd *pw; struct group *gr; struct stat st; | |
extern char **environ; char b[512]; | |
char h(char*s){char _=*s;while(*s)_=*s+++_+1;return _;} | |
char*N(char*_){return _&&strchr(_,S[0])?strrchr(_,S[0])+1:_?_:"";} | |
char*D(char*_){char*n=strrchr(_?_:"",0[S]);if(n)*n=0;return _;} | |
void d(int A,FILE**B){ | |
long c=**(char**)B, C=c==0x38, x[11]={0}, y=0, d; | |
if(c==0x1C||(C&&A!=3)) return; | |
++B,A-=C+1; | |
FILE*P=C?B[1]:stdout,*I=A?B[0]:stdin; | |
C=0; | |
while(I){ | |
while(!feof(I)){ | |
C+=(d=fgetc(I))==10&&(x[y++%11]=ftell(I)); | |
if(d<0&&c=='"'&&!fseek(I,x[y%11],SEEK_SET)&&(c='~')&&!(C=0)) | |
continue; | |
if(d>0&&c!='"'&&fputc(d,P)&&C>=10&&c=='~') | |
break;} | |
fclose(I); | |
I=--A>0?*++B:NULL;} | |
fclose(P);} | |
void L(char*p,int r){ | |
if(r&&S_ISDIR(st.st_mode)){ | |
DIR*d=opendir(p); | |
struct dirent*e; | |
while((e=readdir(d))){ | |
strcpy(b,p); | |
strcat(b,"/"); | |
strcat(b,e->d_name); | |
stat(b,&st); | |
L(b,0);} | |
closedir(d); | |
}else{ | |
pw=getpwuid(st.st_uid); | |
gr=getgrgid(st.st_gid); | |
printf("%04o %lu %s %s %lu %s\n",st.st_mode&07777, | |
st.st_nlink,pw->pw_name,gr->gr_name,st.st_size,N(p));}} | |
void e(int A,char**B){ | |
int s=A>1&&!!strchr("\240\237",B[1][0]+B[1][1]); | |
int _=s+**B; | |
B+=s+1; | |
long a=-1; | |
while(--A){ | |
char*s=NULL; | |
int(*f)(const char*,const char*)=NULL; | |
stat(*B,&st); | |
switch(_){ | |
case'\7':if(a<0){pw=getpwnam(*B);a=pw->pw_uid;}else chown(*B,a,st.st_gid);break; | |
case'|':if(a<0){gr=getgrnam(*B);a=gr->gr_gid;}else chown(*B,st.st_uid,a);break; | |
case'\x1b':kill(atoi(B[1]),atoi(&(*B)[1]));return; | |
case'H':f=link;break; | |
case'I':f=symlink;break; | |
case'&':s=N(*B);break; | |
case'K':s=D(*B);break; | |
case'\b':s=*B;break; | |
case'S':unlink(*B);break; | |
case'M':L(*B,1);break; | |
case'R':f=rename;break; | |
case'T':remove(*B);break; | |
case'\x15':rmdir(*B);break; | |
case'\t':mkdir(*B,0755); | |
case's':if(a<0)a=strtol(*B,NULL,8);else chmod(*B,a);break; | |
case'x':chroot(*B);chdir("/");execvp(B[1],B+1);break;} | |
if(f){ | |
f(B[0],B[1]); | |
return;} | |
if(s)puts(s);++B;}} | |
int main(int A,char**B){ | |
char _=**B=h(N(*B))&0x7F; | |
struct utsname u;int i; | |
uname(&u); | |
switch(!!strchr(S,_)+!!strchr(S F,_)+!!strchr(S F O,_)+!!(h(N(*B))==-063)*2){ | |
case 3:while(_=='1'&&*environ)puts(*environ++); | |
while(_=='\x4D'){putchar(_^'4');putchar('\n');} | |
return _=='v'||_=='1'||!puts(_=='>'?getcwd(b,512):u.sysname); | |
case 2:for(i=1;i<A;++i){ | |
char*_=B[i]; | |
B[i]=(char*)fopen(_,access(_,F_OK)!=-1?"r+":"w+"); | |
if(!B[i])B[i]=(char*)fopen(_,"r");} | |
d(A,(FILE**)B);break; | |
case 1:e(A,B);}return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Eat your heart out, busybox! | |
At least some of the features of this tool are probably apparent with a little | |
examination. Once you understand the basic concept, you can discover many of the | |
features by simply looking for which syscalls are used and knocking a couple of | |
brain cells together. However, this little box contains more subtlety than you | |
think! The trick is finding out not some of the things it does, but all of the | |
things it does. | |
Some of the obsfucations I use here are: | |
- Hashing argv[0] to avoid having to explicitly name all of the features | |
- Using the same code to implement several features at once via obtuse | |
conditional logic | |
- Using variables in misleading ways and exploiting the side effects | |
- Replacing argv with file pointers to make some things easier but also confuse | |
anyone researching it with their debugger. Note: this is, strictly speaking, | |
not abusing writable strings as the guidelines bemoan. argv is an array of | |
_pointers_ to strings! | |
- Just because the same number shows up several times doesn't mean it has to | |
have a consistent representation | |
- Bad symbol names and centering all of the code, I guess | |
Note: I recommend naming this file ln.c. The name of the binary is important, | |
and "prog" will not work. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment