抖音自动点赞源码深度解析:无障碍服务、XXTEA加密与并发账本
2026/9/16 15:43:08 网站建设 项目流程

简介:这是一套运营级抖音点赞辅助源码,面向短视频运营研究者、爬虫与自动化脚本学习者,包含自动点赞、自动机器人挂机、免审核到账及抽奖模块,适合用于分析平台交互逻辑与反爬策略,而非直接部署商用。压缩包共2015个文件,以php、js、html、css为主,辅以config、sql、txt说明及apk安装包等,整体171.33MB,目录结构涵盖前后端脚本、接口配置与页面模板,便于按模块拆解学习。已有582人学习/下载,其中php后端业务逻辑、js前端调用链、sql数据表与config配置项对理解自动任务调度、请求签名、账号体系设计有一定参考价值。需强调,此类工具违反平台使用规则,建议仅限技术研究与合规学习场景使用。

1. 一份标着“运营级抖音点赞完整源码”的资源,文件列表通常会让人意外

app.apk、merge.bat、php_xxtea.c、xxtea.c、config,看起来不像是能直接跑起来的东西,但它们恰好暴露了一条完整链路的五个节点:Android 端负责自动挂机操作,PHP 端负责派发任务和记账,XXTEA 负责两端通信加密,merge.bat 负责把新配置打回 APK 重新签名,config 则是这套系统所有开关的汇聚点。真正有价值的不在点击逻辑里,而在“客户端上报一个点赞成功,服务端就加一笔积分,抽奖再把这些积分收回来”的闭环设计。自动机器人本身不复杂,复杂的是让服务端信任一批低成本设备,同时在上报去重、延迟节奏、结算并发上不翻车。想拆这把锁的人在下文能按协议还原路径走一遍;正在做 Android 自动化工具、需要设计任务与账本侧的人,也能直接抄到参数和边界。

2. 自动挂机端如何工作:merge.bat、无障碍服务与任务节流

2.1 merge.bat 在整个自动化源码里的真正角色

先别急着装 App,第一步是看批处理。这类资源为了把服务端地址、xxtea_key、任务参数分发给不同手机,通常会做一套“解包 → 替换 config → 重新打包 → 签名”的流水线,merge.bat 就是这条流水线的入口。

@echo off set APKTOOL=apktool.jar set TOOL_DIR=%~dp0 if not exist unpack ( java -jar %APKTOOL% d release.apk -o unpack ) copy /Y config\service_config.json unpack\assets\service_config.json java -jar %APKTOOL% b unpack -o build.apk call zipalign -f 4 build.apk aligned.apk call apksigner sign --ks release.jks --ks-pass pass:android aligned.apk

这段批处理做了四件事:apktool d把 APK 解包到unpack目录;copy用最新配置覆盖原有 assets 里的 JSON;apktool b重新打包;最后zipalign做 4 字节对齐,apksigner用 keystore 签名。很多运营者改完 PHP 端后只记得换 key,忘了重新签名,结果 APK 装不上,问题就出在这一步。

这里最容易忽略的是签名环节。Android 7.0 之后如果只用 v1 签名,部分机型会提示“安装解析失败”,所以签名命令里需要同时保留 v1 和 v2。另外copy的目标路径要和 Android 端读取路径完全一致,比如客户端写死的是assets/service_config.json,批处理里就不能只丢一个config目录进去。我一般会在批处理末尾加一段where adb && adb install -r aligned.apk,方便本机直装验证。

2.2 AccessibilityService:从系统事件里找到点赞按钮

自动挂机端最常用的不是 root,而是无障碍服务。它不需要系统权限,只要用户手动开启一次,就能读取当前窗口的节点树并模拟点击。核心逻辑集中在onAccessibilityEvent回调里,常见写法是这样的:

public class LikeAccessibilityService extends AccessibilityService { @Override public void onAccessibilityEvent(AccessibilityEvent event) { if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) { return; } AccessibilityNodeInfo root = getRootInActiveWindow(); if (root == null) return; List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText("点赞"); for (AccessibilityNodeInfo node : nodes) { AccessibilityNodeInfo clickable = findClickableParent(node); if (clickable != null && !clickedVideoIds.contains(currentVideoId())) { clickable.performAction(AccessibilityNodeInfo.ACTION_CLICK); clickedVideoIds.add(currentVideoId()); reportTask(currentVideoId()); break; } } } }

findAccessibilityNodeInfosByText是按文本匹配节点,抖音的“点赞”文案经常挂在 TextView 上,真正可点击的往往是它的父容器,所以要先向上找findClickableParentcurrentVideoId()可以从页面结构里取,也可以简单地从当前 Activity 的 View ID 中提取,目的是保证同一个视频只上报一次。

这段代码放到线上最大的问题是回调频率太高。TYPE_WINDOW_CONTENT_CHANGED在页面滑动时会触发几十次,如果在回调里直接做网络上报,服务端会被打爆。常见做法是先写入本地队列,再交给单线程调度器异步消费。

2.3 挂机任务循环与节流参数

点赞动作本身不是瓶颈,节奏才是。一套能跑超过一周的挂机程序,任务循环一定是带随机延迟和小时上限的:

ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(() -> { while (running) { Task task = pullTask(); if (task == null) { sleep(WAIT_NO_TASK); continue; } swipeUp(); sleep(random(INTERVAL_MIN, INTERVAL_MAX)); if (likeCurrent()) { uploadResult(task.getId(), "success"); } sleep(random(3000, 5000)); } });

这里的sleep不是可有可无的减速带。固定sleep(3000)的脚本,行为特征非常明显:每三秒一次上滑、每三次上滑一次点赞,几个小时内就会被风控模型标记。随机窗口的意义是让操作间隔接近真实用户。swipeUp()是上滑切换视频,likeCurrent()内部会通过无障碍节点执行点击。

任务循环的参数建议按下表配置:

参数典型值说明
WAIT_NO_TASK20-30s没有任务时轮询间隔,太短会增加服务端压力
INTERVAL_MIN2000ms两次操作的最小间隔
INTERVAL_MAX3500ms最大间隔,与 min 配合形成随机窗口
MAX_TASK_PER_HOUR30-50小时任务上限,超过就进入休眠
BLACKLISTvideo_id 列表已经不感兴趣或已点赞的视频,防止重复上报

判断一套源码是不是“运营级”,不用看界面,看这三组数字就够了:随机延迟范围、小时任务上限、黑名单去重。三者都有的,说明作者被现实毒打过;只有固定 sleep 的,基本是跑几天就废的 demo。

3. PHP 服务端与 XXTEA 加解密:协议还原与配置坑

3.1 为什么这套源码偏爱 XXTEA 而不是 AES/RSA

php_xxtea.cxxtea.c同时出现,意味着客户端与 PHP 服务端用同一套 XXTEA 实现做通信加密。这种选择很务实:XXTEA 的 C 实现只有一两百行,编译成 so 文件塞进 APK 毫无压力,PHP 侧也有对应的扩展或纯 PHP 实现,不需要像 AES 那样处理 IV、模式、PKCS7 填充,也不用像 RSA 那样考虑性能损耗。

但要注意,XXTEA 是分组加密算法,不是签名算法。它解决的是“抓包看不到明文”的问题,解决不了“服务端不验签导致伪造请求”的问题。很多资源里只有加密没有签名,服务端拿到base64(xxtea(json))就认为是合法客户端,这是最大的隐患。

维度XXTEAAES-CBCRSA
密钥数量1 个1 个一对公私钥
实现复杂度低,适合嵌入 C/PHP中,需处理 IV 和填充高,性能差
典型用途轻量客户端数据通道常规通信加密签名与密钥协商
在灰产源码里的状态密钥硬编码在 config 或 so 中常因 IV 不一致导致调不通很少直接用

3.2 还原请求协议:base64 + xxtea + JSON

抓包一头雾水的时候,先看解密入口。客户端把 JSON 序列化之后,用 XXTEA 加密,再做 base64 编码,最后 POST 到api_url。PHP 端对应的解密函数是这样的:

function decrypt_payload(string $raw, string $xxteaKey): array { $bin = base64_decode($raw, true); if ($bin === false) { throw new RuntimeException('base64 decode failed'); } $json = xxtea_decrypt($bin, $xxteaKey); if ($json === false) { error_log(sprintf( 'xxtea_decrypt failed uid=%s len=%d', $_POST['uid'] ?? '-', strlen($raw) )); throw new RuntimeException('xxtea decrypt failed'); } $data = json_decode($json, true); if (!is_array($data)) { throw new RuntimeException('json decode failed'); } return $data; }

这里有三点值得注意。第一,base64_decode必须用严格模式,第二个参数传true,否则非法字符会被静默丢弃,解密时产生莫名错误。第二,xxtea_decrypt失败时不要把原始密文写进日志,只记 uid 和长度就够了,避免敏感信息泄漏。第三,日志里必须带 uid,线上排查时才能按用户维度定位问题,否则一堆“decrypt failed”根本不知道是谁的包。

响应侧同理:

function encrypt_response(array $data, string $xxteaKey): string { $json = json_encode($data, JSON_UNESCAPED_UNICODE); return base64_encode(xxtea_encrypt($json, $xxteaKey)); }

JSON_UNESCAPED_UNICODE防止中文被转成\uXXXX,减少流量体积。两端只要 key 一致、实现一致,这条链路就能跑通。

3.3 config 里最常见的字段与作用

config在这类资源里通常不是一个文件,而是一组配置。服务端要下发的不只是 API 地址,还包括加密开关、任务频率和结算策略。一个典型的 config 结构是这样:

return [ 'api_url' => 'https://api.example.com/api.php', 'xxtea_key' => '0123456789abcdef', 'encrypt_body' => true, 'task_interval' => 3000, 'max_task_per_hour' => 50, 'automatic_credit' => true, ];

api_url决定 App 往哪上报;xxtea_key是两端共用的 16 字节密钥;encrypt_body是兼容老客户端的开关,置为 false 时 App 直接发明文 JSON,调试方便但上线必须关掉;task_intervalmax_task_per_hour是自动挂机端的节流参数;automatic_credit对应标题里的“无需审核自动挂机到账”,置为 true 表示客户端上报成功后服务端自动加积分,不做人工审核。

这个automatic_credit是最危险的一个开关。开成 true,意味着服务端完全信任客户端上传的 task_id、video_id、status 字段。只要把报文里的 status 改成 success 重放,就能无限刷积分。正规一点的做法是把这个开关设成 false,服务端至少要校验任务是否真实存在、是否已过期、是否被其他设备领走过。

3.4 服务端接口结构与参数约定

整套系统围绕四个接口展开:

接口动作核心参数说明
task/get获取任务uid, device_id, video_id返回需要点赞的视频列表
task/report上报结果task_id, video_id, status写入任务流水并触发加积分
user/balance查询余额uid返回当前积分和可提现额度
lottery/draw抽奖uid, cost扣积分并按权重发放奖品

task/report是整套系统的命脉。低劣实现里没有去重,一个 task_id 上报十次就给十分;稍微好一点的会在 task_report 表上加唯一索引;运营级的还会校验上报时间与任务下发时间之间的间隔,如果间隔小于 3 秒就判定异常,因为真实用户不可能这么快看完一个视频。

4. “无需审核自动挂机到账”背后的账本与抽奖并发边界

4.1 到账为什么可以做到“无需审核”

所谓“无需审核自动挂机到账”,本质是服务端把审核从流程中拿掉了。客户端上报一个成功状态,服务端就直接执行加积分操作,中间没有任何人工或程序化复核。这套机制能运转的前提,是服务端信任设备上报的数据。

但信任必须用数据库约束兜底。最常见的防重做法是给任务上报表加联合唯一索引:

ALTER TABLE task_report ADD UNIQUE KEY uk_task_uid (task_id, uid);

加上这个索引后,同一个任务被同一用户重复上报时,第二次插入会直接报主键冲突,事务回滚,积分不会被重复累加。没有这条索引,再谈“运营级”都没有意义。除了唯一索引,task_report 表里至少要保留uiddevice_idtask_idvideo_idipevent_time六个字段,后续风控回查时才能定位到具体设备和网络。

4.2 余额账本与并发更新

加积分不是一条简单的UPDATE,否则并发场景下账目很容易错乱。一个可对账的结算流程是这样:

START TRANSACTION; SELECT coin FROM user_balance WHERE uid = ? FOR UPDATE; UPDATE user_balance SET coin = coin + ? WHERE uid = ?; INSERT INTO coin_log (uid, change_amount, reason, ref_id) VALUES (?, ?, 'task_reward', ?); COMMIT;

FOR UPDATE对用户余额行加了行级锁,保证同一个用户的两次加积分请求不会互相覆盖。coin_log是流水表,ref_id必须对应 task_report 表的自增 ID,这样对账时每一笔积分都能回溯到一次真实任务。如果看到某套源码只有一个UPDATE user_balance SET coin = coin + 1,没有流水表,说明它的账本根本没有审计能力,一旦被人刷量,只能从数据库日志里手工捞数据。

4.3 抽奖模块的权重与库存扣减

抽奖听起来简单,但权重和库存是一对天然的并发矛盾。常见实现是“按权重随机抽中,再扣库存”:

$total = array_sum(array_column($prizes, 'weight')); $roll = mt_rand(1, $total); foreach ($prizes as $prize) { $roll -= $prize['weight']; if ($roll <= 0) { $hit = $prize; break; } } if ($hit['stock'] >= 0) { $ok = $pdo->prepare( 'UPDATE lottery SET stock = stock - 1 WHERE id = ? AND stock > 0' )->execute([$hit['id']]); if (!$ok) { // 库存已经为 0,重新抽奖,最多 5 次 return draw_with_retry($uid, 5); } }

权重抽奖的思路是:先算总权重,再随机一个落在总权重范围内的数,每次减去当前奖品权重,第一个减到 0 以下的奖品就是中奖项。比如总权重是 100,roll 到 80,减去权重 50 后剩 30,再减去权重 30 后是 0,那么 5 元红包被命中。

库存扣减必须带着AND stock > 0条件。没有这个条件时,两个并发请求同时读到库存为 1,都执行 UPDATE,最后库存变成 -1。设置最多重抽 5 次是因为极端情况下所有高权重奖品都缺货,递归不设上限会把进程拖死。

抽奖参数建议单独建表维护,方便运营调概率:

字段类型说明
prize_idint奖品 ID
prize_namevarchar奖品名称
weightint相对权重,数字越大中奖概率越高
stockint库存,-1 表示不限
min_coinint每次抽奖消耗的积分数

抽奖消耗的积分和点赞获得的积分必须放在同一个coin_log里,形成账本闭环。如果抽奖用独立积分体系,就会产生双货币问题,用户刷完赞之后积分和抽奖积分对不上,只能人工调账。我见过好几个项目死在这个点上。

5. 拿到源码后先自检:密钥扫描、协议自检与合规改造

5.1 先扫一遍 APK 里有没有硬编码密钥

xxtea.c编进 so 文件后,字符串常量并不会消失。拿到任何资源包,第一步就是解包扫描密钥:

mkdir -p check && cd check unzip -q ../release.apk grep -a -rn "xxtea_key\|0123456789abcdef" . | head -20

如果 APK 里的密钥和 PHP 端 config 里的一致,说明这份源码任何一个拿到手的人都能伪造请求。上线前第一件事是生成新的 16 字节随机密钥,同步修改 PHP 端php_xxtea.c对应的 key,再用 merge.bat 重新签名打包。

5.2 服务端加一层轻量协议自检

不引入复杂风控的情况下,最有效的自检是时间戳和任务去重:

if (time() - $data['ts'] > 120) { http_response_code(403); exit('stale'); } $dupKey = 'task:' . $data['task_id'] . ':' . $data['uid']; if (cache_get($dupKey)) { http_response_code(409); exit('duplicate'); } cache_set($dupKey, 1, 3600);

ts是客户端上报时间戳,超过 120 秒的请求直接拒绝,可以把离线重放的数据挡掉一大部分。dupKey用 Redis 缓存做秒级去重,比查数据库唯一索引更快,但两者要同时保留,缓存是防并发穿透,唯一索引是最终兜底。

5.3 更稳的路径:从模拟点击转向官方开放能力

无障碍模拟点击本质上是在和风控对抗,封号成本远大于点赞收益。如果把方案改成正规互动场景,可以直接走抖音开放平台的客户端能力和侧边栏接入流程,让真实用户在活动页面完成任务。这套源码里的用户积分、抽奖、流水账本都能保留,把“点赞上报”替换成“活动参与上报”,就成了一个合规的用户增长工具。接入前先到开放平台后台确认能力开通范围,再用服务端 API 做数据校验,配合已有的 coin_log 账本,项目反而更有长期价值。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询