import gdb gr = gdb.execute state = {"n": 0, "any": 0, "pend": None, "base": None, "chits": 0, "cleared": 0, "whits": 0, "wrote": 0} def u32(a): return int(gdb.parse_and_eval("*(unsigned int*)0x%x" % a)) def u64(a): return int(gdb.parse_and_eval("*(unsigned long*)0x%x" % a)) def ioc(d, t, nr, size): return (d << 30) | (size << 16) | (t << 8) | nr VIDHEAP = ioc(3, 0x46, 0x4a, 0xb8) def glbase(): try: pid = gdb.selected_inferior().pid for line in open("/proc/%d/maps" % pid): parts = line.split() if "libnvidia-eglcore" in line and int(parts[2], 16) == 0: return int(parts[0].split("-")[0], 16) except Exception: pass return None class BC(gdb.Breakpoint): def __init__(self, addr): super().__init__("*0x%x" % addr, internal=False) self.silent = True def stop(self): state["chits"] += 1 try: obj = int(gdb.parse_and_eval("$rdi")) n = int(gdb.parse_and_eval("$rsi")) cnt = u32(obj + 0x22efc) for i in range(0, min(cnt, 32)): p = u64(obj + 0x1428 + i * 8) if not p: continue tgt = p + n * 0x10 try: v16 = int(gdb.parse_and_eval("*(unsigned short*)0x%x" % (tgt + 0xe))) if v16 == 0xffff: gr("set {unsigned short}0x%x = 0" % (tgt + 0xe)) gr("set {unsigned int}0x%x = 0" % tgt) gr("set {unsigned short}0x%x = 0" % (tgt + 0xc)) state["cleared"] += 1 print("CLEAR#%d obj=0x%x n=0x%x tgt=0x%x" % (state["cleared"], obj, n, tgt), flush=True) except Exception: pass except Exception: pass return False class BW(gdb.Breakpoint): def __init__(self, addr): super().__init__("*0x%x" % addr, internal=False) self.silent = True def stop(self): state["whits"] += 1 try: rbx = int(gdb.parse_and_eval("$rbx")) sub = u64(rbx + 0x70) obj2 = u64(sub + 0x58) off = u32(obj2 + 0x60) holder = u64(obj2 + 0x58) base2 = u64(holder + 0x58) word = base2 + off val = u32(word) if state["whits"] <= 6 or val == 0: print("WORD#%d addr=0x%x val=0x%x" % (state["whits"], word, val), flush=True) if val == 0: gr("set {unsigned int}0x%x = 1" % word) state["wrote"] += 1 except Exception: pass return False class IOC(gdb.Breakpoint): def __init__(self): super().__init__("ioctl", internal=False) self.silent = True def stop(self): if state["base"] is None: b = glbase() if b: state["base"] = b print("GLBASE 0x%x" % b, flush=True) try: BC(b + 0xB33D30) BW(b + 0xDCEBD9) print("BC-BW-SET", flush=True) except Exception as e: print("bpset-fail %s" % e, flush=True) try: req = int(gdb.parse_and_eval("$rsi")) & 0xFFFFFFFF arg = int(gdb.parse_and_eval("$rdx")) except Exception: return False if state["pend"] is not None: try: st = u32(state["pend"] + 0x14) at = u32(state["pend"] + 0x38) off = u64(state["pend"] + 0x68) print("PREV149-OUT st=0x%x attr=0x%x off=0x%x" % (st, at, off), flush=True) except Exception as e: print("PREV149-STATUS unreadable %s" % e, flush=True) state["pend"] = None if req != VIDHEAP: return False state["any"] += 1 try: fn = u32(arg + 0x08) size = u64(arg + 0x58) attr = u32(arg + 0x38) owner = u32(arg + 0x28) flags = u32(arg + 0x34) except Exception: return False if fn == 2 and size == 0x10000 and (attr & 0xf000) == 0x2000 and owner == 0x474C0000: state["n"] += 1 print("HIT149 n=%d attr=0x%x flags=0x%x owner=0x%x align=0x%x" % ( state["n"], attr, flags, owner, u64(arg + 0x60)), flush=True) if state["n"] == 1: gr("bt 12") newattr = attr & 0xFFFFCFFF gr("set {unsigned int}0x%x = 0x%x" % (arg + 0x38, newattr)) print("FLIP149 attr 0x%x -> 0x%x" % (attr, newattr), flush=True) state["pend"] = arg return False try: IOC() print("BPS-SET", flush=True) except Exception as e: print("bpset-fail %s" % e, flush=True) gr("set pagination off") gr("set confirm off") try: gr("run") except Exception as e: print("runend %s" % e, flush=True) print("T120-DONE n=%d any=%d chits=%d cleared=%d whits=%d wrote=%d" % ( state["n"], state["any"], state["chits"], state["cleared"], state["whits"], state["wrote"]), flush=True) gr("quit")