docs: 补充mem_scanner和web_setup SOP;优化代码风格和上下文管理

This commit is contained in:
Liang Jiaqing
2026-02-16 22:33:50 +08:00
parent dbc28fbc35
commit 67c7b3fa71
5 changed files with 62 additions and 15 deletions

View File

@@ -247,10 +247,7 @@ class TMWebDriver:
return result['data']
def _remote_cmd(self, cmd):
resp = requests.post(self.remote,
headers={"Content-Type": "application/json"},
json=cmd).json()
return resp
return requests.post(self.remote, headers={"Content-Type": "application/json"}, json=cmd).json()
def get_all_sessions(self):
if self.is_remote:

View File

@@ -31,3 +31,20 @@ python ../memory/mem_scanner.py <PID> "pattern" --llm
## 3. 注意事项
- **权限**: 并非强制要求管理员权限,但需具备对目标进程的 `PROCESS_QUERY_INFORMATION``PROCESS_VM_READ` 权限。
- **效率**: 搜索大块内存时,尽量提供更唯一的特征码以减少误报。
## 4. 典型场景CE式差集扫描定位动态字段已验证
用于定位微信等自绘UI中「当前会话标题」等随操作变化的内存字段。
**方法类似Cheat Engine找游戏数值**
1. 找到主窗口PIDWeixin.exe有多个进程用win32gui.GetWindowThreadProcessId取有窗口的那个
2. 切到会话A → `scan_memory(pid, "人名A", mode="string")` → 得地址集S_A
3. 切到会话B → `scan_memory(pid, "人名B", mode="string")` → 得地址集S_B
4. 差集S_A独有地址A时有、B时无= 候选地址
5. 切回A → 用ReadProcessMemory逐个读候选地址确认内容变回"人名A"的即为目标
6. 再切第3、4个人交叉验证
**坑点:**
- 搜索切换会污染结果(搜索框缓存也含人名),最终验证应用列表点击而非搜索
- 地址是绝对虚拟地址进程重启后失效需重新校准约10秒
- ReadProcessMemory读UTF-8`raw.split(b'\x00')[0].decode('utf-8')`提取干净文本
- 微信主进程名为Weixin.exe非WeChat.exe

View File

@@ -19,6 +19,37 @@ browser = "chrome" if shutil.which("chrome") else "msedge" # Edge内置必存
- Edge: `start "" "https://microsoftedge.microsoft.com/addons/detail/tampermonkey/iikmkjmpaadaobahmlepeloendndfphd"`
2. 提示用户点击"安装"并确认。
## 阶段 1.5:开启「允许运行用户脚本」
**前置**TM 已安装,但 Chrome 可能默认未开启此权限。
需打开 TM 的扩展详情页,手动开启相关开关。
### 自动打开详情页
1. 从文件系统读取 TM 扩展 ID
```python
import os, json, glob
ext_dir = os.path.expandvars(r'%LOCALAPPDATA%\Google\Chrome\User Data\Default\Extensions')
for eid in os.listdir(ext_dir):
for ver in glob.glob(os.path.join(ext_dir, eid, '*')):
mf = os.path.join(ver, 'manifest.json')
if os.path.isfile(mf):
with open(mf, encoding='utf-8') as f:
m = json.load(f)
if 'tampermonkey' in m.get('name','').lower() or 'tampermonkey' in m.get('description','').lower():
tm_id = eid; break
```
2. 导航到 `chrome://extensions/?id={tm_id}`
- ⚠️ `chrome://` 协议无法通过命令行参数或 JS(`window.open`) 打开
- ✅ 用 ljqCtrl需先打开一个 Chrome 窗口并置顶)或剪贴板+地址栏方案:
```python
# 剪贴板方案写入URL → Ctrl+L → Ctrl+V → Enter
import win32clipboard
win32clipboard.OpenClipboard(); win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(f'chrome://extensions/?id={tm_id}')
win32clipboard.CloseClipboard()
# 然后用 ljqCtrl 或 SendKeys 发送 Ctrl+L, Ctrl+V, Enter
```
3. 提示用户在详情页中开启「允许运行用户脚本」开关。
## 阶段二:安装 ljq_web_driver.user.js
**脚本路径**: `../assets/ljq_web_driver.user.js`

View File

@@ -41,7 +41,7 @@ class SiderLLMSession:
return full_text
class ClaudeSession:
def __init__(self, api_key, api_base, model="claude-opus", context_win=10000):
def __init__(self, api_key, api_base, model="claude-opus", context_win=9000):
self.api_key, self.api_base, self.default_model, self.context_win = api_key, api_base.rstrip('/'), model, context_win
self.raw_msgs, self.lock = [], threading.Lock()
def _trim_messages(self, messages):
@@ -53,7 +53,7 @@ class ClaudeSession:
if (msg_len := len(msg['prompt'])) + current <= target:
result.append(msg); current += msg_len
else: break
if current > 10000 * 4: print(f'[DEBUG] Whole context length {current//4}.')
if current > self.context_win * 3.6: print(f'[DEBUG] {len(result)} contexts, whole length {current//4} tokens.')
return result[::-1] or messages[-2:]
def raw_ask(self, messages, model=None, temperature=0.5, max_tokens=4096):
model = model or self.default_model

View File

@@ -875,14 +875,16 @@ def get_html(driver, cutlist=False, maxchars=28000, instruction=""):
rr = driver.execute_js(js_findMainList + js_findMainContent + """
return findMainList(findMainContent(document.body));""")
sel = rr.get("selector", None) if isinstance(rr, dict) else None
if not sel: return html[:maxchars]
if sel:
s = BeautifulSoup(str(soup), "html.parser"); items = s.select(sel)
hit = [it for it in items if instruction and instruction.strip() and instruction in it.get_text(" ",strip=True)]
keep = hit[:6] if hit else items[:3]
for it in items:
if it not in keep: it.decompose()
s = optimize_html_for_tokens(s)
return str(s)[:maxchars]
ss = str(optimize_html_for_tokens(s))
else: ss = html
if len(ss) > maxchars: ss = ss[:maxchars] + ' ... [TRUNCATED]'
return ss
def execute_js_rich(script, driver):
try: start_temp_monitor(driver)