利用沙盒技术破解APP的API协议加密

article/2025/9/16 17:10:07

项目地址:https://github.com/tbruceyu/AppCaller

无聊的需求

前段时间闲的没事,经常刷某视频App。里面有很多有才的人,突然想把他们的视频都给下载下来在电脑上面存起来慢慢看。正好这段时间比较空闲,就尝试去破解一下它的Http加密协议。
作为一个主要工作在客户端上的码农,第一时间想到了去抓包看一下他们的App协议。
在这里插入图片描述
可以看到,通过调用http://103.107.217.65/rest/n/feed/profile2这个接口就可以去获取到这个主播的视频了。然后通过分页加载即可下载所有的视频。但是通常的App都会对请求做保护,防止被爬虫抓取。看了下我们的请求里面有一个sig xxxxxx的字段。看来我们需要去破解这个签名算法才行。

通用操作

通常的破解都是用Java的反编译工具去找到App的上层加密调用函数,找到Java层的核心加密函数的位置,然后再用静态分析和动态调试汇编代码,最后自己手动实现这个加密算法。这个方法是最完美的破解方案,但是难度巨大,而且如果App升级后,又需要重新去完整分析一遍。对技术的要求还是很高的。而且现在越来越多的APP会把so里面的符号表去掉,还会混淆核心函数的实现,加大分析难度。以某音的加密libcms.so为例,里面的汇编代码都被混淆了,用IDA的F5插件转化后的代码也根本读不懂。里面连RegisterNative函数调用都找不到。
在这里插入图片描述
如果要用这种方式去破解移动App的协议,无疑要花费大量的时间和精力,而且我自己本身也没有太多逆向分析的经验,那我们能不能用其他的方式去做呢?

新的思路

在Android开发生态下,有很多的黑科技,其中一种就是应用双开技术,比如BLE平行空间、VirtualApp等。好在16年的时候VirtuapApp开源后我有去研究过它的代码,核心原理就是利用Java动态代理和反射技术,自己模拟一个Android的Framework,架设在App和系统之间,达到欺骗App和系统的目的。知道了沙盒技术的原理。思路来了:

利用沙盒把App放到自己能够控制的环境里面去执行,然后在里面启动一个Web服务器,通过远程Http调用访问沙盒里的App,去调用核心加密逻辑,计算出密钥,然后返回给客户端。这样就能够达到破解App的加密算法的目的。
废话不说,开干!

分析上层加密函数

apktool 工具先把这个App的包解出来:

xxx@bogon:~/temp/kuaishou$ apktool  d kuaishou.apk
I: Using Apktool 2.4.0 on kuaishou.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /Users/xxx/Library/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Baksmaling classes10.dex...
I: Baksmaling classes11.dex...
I: Baksmaling classes12.dex...
I: Baksmaling classes13.dex...
I: Baksmaling classes14.dex...
I: Baksmaling classes2.dex...
I: Baksmaling classes3.dex...
I: Baksmaling classes4.dex...
I: Baksmaling classes5.dex...
I: Baksmaling classes6.dex...
I: Baksmaling classes7.dex...
I: Baksmaling classes8.dex...
I: Baksmaling classes9.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
xxx@bogon:~/temp/kuaishou$

然后我们去里面搜索sig字符串,看在哪里加入到Http请求里的:

xxx@bogon:~/temp/kuaishou$ cd kuaishou/
xxx@bogon:~/temp/kuaishou/kuaishou$ grep sig . -rw
./smali_classes10/com/xiaomi/push/service/p.smali:    const-string/jumbo v0, "sig"
./smali_classes10/com/xiaomi/push/service/XMPushService$c.smali:    const-string/jumbo v3, "invalid-sig"
./smali_classes10/com/xiaomi/push/service/XMPushService$c.smali:    const-string/jumbo v4, "SMACK: bind error invalid-sig token = "
Binary file ./lib/armeabi-v7a/libgodzilla.so matches
Binary file ./lib/armeabi-v7a/libBugly.so matches
Binary file ./lib/armeabi-v7a/libksimage.so matches
Binary file ./lib/armeabi-v7a/libCGE.so matches
Binary file ./lib/armeabi-v7a/libawesomecache.so matches
Binary file ./lib/armeabi-v7a/libkwsgmain.so matches
Binary file ./lib/armeabi-v7a/libxylivesdk.so matches
Binary file ./lib/armeabi-v7a/libquic.so matches
Binary file ./lib/armeabi-v7a/libYTFaceReflect.so matches
./smali_classes2/com/yxcorp/gifshow/retrofit/k.smali:    const-string/jumbo v2, "sig"
xxx@bogon:~/temp/kuaishou/kuaishou$

前面几个smali文件明显是小米的渠道Push相关的代码,可以忽略,肯定是./smali_classes2/com/yxcorp/gifshow/retrofit/k.smali这一个retrofit里面加入的了。我们打开这个文件,果然发现这个sig就是里面的一个叫computeSignature的方法返回的Pair的first,并且参数就是okhttp的Request,很明显是用来计算密钥的。

# virtual methods
.method public final computeSignature(Lokhttp3/Request;Ljava/util/Map;Ljava/util/Map;)Landroid/util/Pair;.locals 5.annotation system Ldalvik/annotation/Signature;value = {"(","Lokhttp3/Request;","Ljava/util/Map","<","Ljava/lang/String;","Ljava/lang/String;",">;","Ljava/util/Map","<","Ljava/lang/String;","Ljava/lang/String;",">;)","Landroid/util/Pair","<","Ljava/lang/String;","Ljava/lang/String;",">;"}.end annotation.prologue.line 23const-string/jumbo v0, ""invoke-static {p2, p3}, Lcom/yxcorp/retrofit/f/a;->b(Ljava/util/Map;Ljava/util/Map;)Ljava/util/List;move-result-object v1invoke-static {v0, v1}, Landroid/text/TextUtils;->join(Ljava/lang/CharSequence;Ljava/lang/Iterable;)Ljava/lang/String;move-result-object v0.line 24new-instance v1, Landroid/util/Pair;const-string/jumbo v2, "sig".line 25invoke-static {}, Lcom/yxcorp/gifshow/b;->a()Lcom/yxcorp/gifshow/e;move-result-object v3invoke-interface {v3}, Lcom/yxcorp/gifshow/e;->b()Landroid/app/Application;move-result-object v3sget-object v4, Lorg/apache/internal/commons/io/a;->f:Ljava/nio/charset/Charset;invoke-virtual {v0, v4}, Ljava/lang/String;->getBytes(Ljava/nio/charset/Charset;)[Bmove-result-object v0sget v4, Landroid/os/Build$VERSION;->SDK_INT:Iinvoke-static {v3, v0, v4}, Lcom/yxcorp/gifshow/util/CPU;->a(Landroid/content/Context;[BI)Ljava/lang/String;move-result-object v0invoke-direct {v1, v2, v0}, Landroid/util/Pair;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V.line 24return-object v1
.end method

这段Smili转化成Java大致如下:

    public final Pair<String, String> computeSignature(Request request, Map<String, String> map, Map<String, String> map2) {return new Pair<>("sig", CPU.a(com.yxcorp.gifshow.b.a().b(), TextUtils.join("", a.b(map, map2)).getBytes(org.apache.internal.commons.io.a.f), VERSION.SDK_INT));}

这里可以看到,计算签名和request参数根本没有关系,那么map和map2分别是什么呢?此时我们可以祭出Hook大法。我们就可以去写一个插件去Hook看一下方法参数里面的两个Map分别是什么。站在巨人的肩膀上(用现成的),我这里用的VirtualHook这个库来Hook打印的。当然我们也可以用Xposed或者VirtualPosed去Hook。

package lab.galaxy.demeHookPlugin;import android.util.Log;
import android.util.Pair;import java.util.Map;public class Hook_computeSignature {public static String className = "com.yxcorp.gifshow.retrofit.k";public static String methodName = "computeSignature";public static String methodSig = "(Lokhttp3/Request;Ljava/util/Map;Ljava/util/Map;)Landroid/util/Pair;";public static Pair<String, String> hook(Object thiz, Object request, Map<String, String> map, Map<String, String> map2) {Log.d("YAHFA", "map:" + map.toString());Log.d("YAHFA", "map2:" + map2.toString());return backup(thiz, request, map, map2);}public static Pair<String, String> backup(Object thiz, Object request, Map<String, String> map, Map<String, String> map2) {Log.e("YAHFA", "should not be here");return null;}
}

配合抓包工具和第二,三个map的打印结果可以发现其实map就是所有的URL Query,map2就是所有的POST的内容

10-14 15:50:01.003 30075-30253/com.smile.gifmaker D/YAHFA: map:{isp=, mod=vivo(vivo X7), pm_tag=, lon=333.355416, country_code=CN, kpf=ANDROID_PHONE, extId=85db4aca4443a3c46a5bac6ed1c78836, did=ANDROID_0b171a80c3ff2d40, kpn=KUAISHOU, net=WIFI, app=0, oc=BAIDU, ud=0, hotfix_ver=, c=BAIDU, sys=ANDROID_5.1.1, appver=6.4.0.9003, ftt=, language=zh-cn, iuid=, lat=33.33333, did_gt=1571111544356, ver=6.4, max_memory=256}
10-14 15:50:01.003 30075-30253/com.smile.gifmaker D/YAHFA: map2:{source=1, volume=0.19, browseType=1, seid=52203040-6dce-1111-b08d-d9ae060c2718, pv=false, needInterestTag=false, client_key=3c2cd3f3, coldStart=false, count=20, pcursor=, os=android, refreshTimes=1, id=10, type=7, page=1}

field。有了这些分析,我们接下来就开始去开始实现我们的想法了。

反射调用加密函数

VirtualApp实现了一套很方便的反射架构,我们可以直接拿来用。不过需要注意一下,由于这里需要反射的是应用的类,而VirtualApp的反射框架是直接反射的系统的类,加载时机是virtualapp自身被fork出来的时候,所以是可以直接加载使用的,而我们要反射的是应用内的类,这些类是在应用的Application创建的时候新建的ClassLoader加载的(LoadedApk.makeApplication)。而我们在VirtualApp里的类环境是相对于这个app的父环境。所以我们需要用新创建的这个ClassLoader才能够加载App内我们需要调用到的类。关于这块有疑惑的同学可以去了解一下Java类的双亲委派的加载机制。代码如下:

package plugins.kuaishou.com.yxcorp.gifshow.retrofit;import android.util.Pair;
import mirror.RefClass;
import mirror.RefMethod;public class k {public static void init(ClassLoader classLoader) {try {TYPE = RefClass.load(k.class, classLoader.loadClass("com.yxcorp.gifshow.retrofit.k"));} catch (ClassNotFoundException e) {e.printStackTrace();}}public static Class<?> TYPE;public static RefMethod<Pair<String, String>> computeSignature;
}

接下来然后我们可以写一个简单的测试函数把抓包工具抓取到的GET Query和POST Fields去除POST里的sig组合成两个map,然后通过

Pair<String, String> res = k.computeSignature.call(instance, null, queryParams, fieldParams);
Log.d("test", "sig:" + res.second);

去调用看一下结果是否和抓包工具里面的相同。我这里已经验证了这个方法就是计算签名的,就不做过多的赘述了。

实现一个简单的Http服务

在Java世界里的现成的Http服务库太多了,我们这里选择了使用Netty库来架设Http服务。Netty库是业界广泛使用的一个NIO实现的异步事件驱动网络框架,并且Netty自身就带了Http的Handler,不用花什么功夫就能做出来。大致就下面这么几行代码
在这里插入图片描述

在VirtualApp的镜像App里加入服务

考虑到大部分的应用的加密模块都会做签名校验,一般会在Application创建的时候去初始化,所以我们的VirtualApp里面多开启动的App都是在一个新的子进程里。在VirtualApp环境里里子App的Application的onCreate调用就在VClientImpl的bindApplicationNoCheck里。所以我们的服务需要是在这之后启动。我们这里简单的抽象包装了一下,万一以后要增加其他的App呢。

package plugins;import android.content.Context;import com.tby.http.SmHttpRequest;import java.util.List;
import java.util.Map;public interface IPlatformPlugin {void init(Context context);SmHttpRequest process(String url, String commonParams, Map<String, String> fields, Map<String, List<String>> headers);
}

我们把这个功能抽象成了init和process两步初始化的时候会把App的Application传入进去,而处理就是具体要做的工作。要新增加一个App直接去实现这两个接口即可。
我们简单的设计了客户端一个请求协议:
在这里插入图片描述
里面包含请求的URL,commonParams用于区分App的一些公共参数,field是所有的POST Fields,header就是所有的HTTP请求头。服务器返回就直接在这个格式里面移除commonParams,插入签名字段就可以了。
接下来就是体力活编写启动Http服务的工作了:

MainServerThread thread = new MainServerThread(port);
thread.addPathHandler("/api", new IPathHandler() {@Overridepublic void handleRequest(ChannelHandlerContext ctx, FullHttpRequest httpRequest) throws Exception {String body = HttpServerUtils.getBody(httpRequest);JSONObject jsonObject = new JSONObject(body);String url = jsonObject.getString("url");String commonParams = jsonObject.getString("commonParams");Map<String, List<String>> headers = JsonUtil.parseHeaders(jsonObject.getJSONObject("header"));Map<String, String> fields = JsonUtil.parseFields(jsonObject.optJSONObject("field"));SmHttpRequest request = plugin.process(url, commonParams, fields, headers);HttpServerUtils.send(ctx, packageResult(request).toString(), HttpResponseStatus.OK);}
});
thread.start();

下面就是去PC环境上运行这个架设在手机端上的远程服务了。我这手机肯定很高兴:平时都是我去调用服务,这次终于轮到你们来调用我了: )
现在App上面把我们的App运行起来,如下图所示:

在这里插入图片描述

接下来在终端下去测试一下。先去查一下手机的IP地址,然后用curl请求:

xxx@bogon:~$ curl http://xxx.xxx.xxx.xxx:8889/api -X POST -d ‘{ “url”: “http://api.ksapisrv.com/rest/n/feed/profile2?app=0&kpf=ANDROID_PHONE&ver=6.4&c=BAIDU”, “commonParams”: “mod=Xiaomi%28MI%208%29&appver=6.4.0.9003&ftt=K-F-T&isp=CTCC&kpn=KUAISHOU&lon=333.337841&language=zh-cn&sys=ANDROID_9&max_memory=512&ud=0&country_code=cn&pm_tag=11694575470&oc=BAIDU&hotfix_ver=&did_gt=153xxxxx91012&iuid=&net=WIFI&did=ANDROID_a1dfcb2b57035073&lat=333.979012”, “field”: { “token”:"", “user_id”:“3848”, “lang”:“zh”, “count”:“30”, “privacy”:“public”, “referer”:“ks%3A%2F%2Fprofile%2F3848%2F5246693579318535881%2F1_i%2F1633500022418448386_h61%2F8”, “browseType”:“1”, “client_key”: “xxx”, “os”: “android” }, “header”: { “User-Agent”: [“kwai-android”], “Accept-Language”: [“zh-cn”], “X-REQUESTID”: [“193601906”], “Host”: [“api.ksapisrv.com”] } }’
{“url”:“http://api.ksapisrv.com/rest/n/feed/profile2?app=0&kpf=ANDROID_PHONE&ver=6.4&c=BAIDU&mod=Xiaomi%28MI%208%29&appver=6.4.0.9003&ftt=K-F-T&isp=CTCC&kpn=KUAISHOU&lon=333.337841&language=zh-cn&sys=ANDROID_9&max_memory=512&ud=0&country_code=cn&pm_tag=11694575470&oc=BAIDU&hotfix_ver=&did_gt=1539073091012&iuid=&net=WIFI&did=ANDROID_a1dfcb2b57035073&lat=333.979012”,“header”:{“User-Agent”:[“kwai-android”],“Accept-Language”:[“zh-cn”],“X-REQUESTID”:[“193601906”],“Host”:[“api.ksapisrv.com”]},“method”:0,“field”:{“token”:"",“user_id”:“3848”,“lang”:“zh”,“count”:“30”,“privacy”:“public”,“referer”:“ks%3A%2F%2Fprofile%2F3848%2F5246693579318535881%2F1_i%2F1633500022418448386_h61%2F8”,“browseType”:“1”,“client_key”:“xxx”,“os”:“android”,“sig”:"8a2fb705bed7471328f99d7f3d91f928"}}
xxx@bogon:~$

如何防范

我们这个方案是基于VirtualApp的沙盒环境做的,直接用现有的双开检测方案即可。通过检测应用的工作目录路径是否是正常的/data/data/目录是否正常即可。

题外话

在实现这个项目的过程中愈发觉得在Android平台下的App的安全真的很难做。这次破解的这个App本身是很容易破解的,后来我又尝试去破解了另外一个很火的短视频App,过程比较曲折一些,但是一样很快就分析破解了。就算我们能够通过双开检测来从上层去防范应用被注入,但是Android平台本身是开源的,我们完全可以在系统上面直接注入类似这样的Hack代码去直接调用某一个应用的一些敏感函数,如何防范这种方式的注入?看起来只能混淆得更深才行了。不过始终没有绝对的安全,最重要的还是服务端的防爬取做好,端控、频控做好。而在客户端上能够提高破解门槛,杜绝大部分的心怀不轨的用户就行了。
另外关于Android的沙盒程序真是一个神器,用来分析和其他应用都十分有用。试想一下你编译了一个Debug版本的VirtualApp,就能够去直接调试其他的应用。用来做一些竞品性能分析,动态调试,关键技术分析等都十分有用。

声明

本项目仅用于学习使用,严禁用于任何商业用途


http://chatgpt.dhexx.cn/article/pdOgAX8D.shtml

相关文章

记一次结合fiddler逆向破解app注册码

某天测试app时&#xff0c;需要注册码才能进入应用&#xff0c;二话不说开始进行破解… 详细过程 运行app时会弹出先输入注册码的弹框&#xff0c;只有输入正确的注册码才可进入。 共采用了3种尝试方式 1.暴力hook 搜索字符串“请输入注册码”&#xff0c;定位到几个可疑函…

【移动安全基础篇】——26、两个简单app破解

1. 试用版软件破解 使用 ApkIde 打开要破解的 app 进行反编译 分别显示各个按钮的相关 smali 代码 将 v0 置为专业版的密钥 保存后重新编译&#xff0c;破解成功2. 网络验证 使用 apkIde 对目标 app 进行反编译操作 定位到点击函数中&#xff0c;分析其中的操作 找到网络连接…

逆向破解思路和获取app的代码,脱壳操作(一)

.我们的app首先是经过我们写代码、最后经过签名、打包最后生成.app文件&#xff0c;那么这个.app的文件在哪里呢&#xff0c;我用我自己的项目做个例子大致他的位置在这里&#xff1a; 他这个其实就是包含我们项目中的资源和我们写的代码&#xff0c;我们要学习逆向那么其实就是…

逆向破解思路和获取app的代码,脱壳操作(四)

加壳 什么是加壳&#xff1f; 我们的ipa文件上传appstore&#xff0c;苹果会给我们做一个加密&#xff0c;其实我们运行在内存中的过程是一个加密的壳程序&#xff0c;当然在手机中我们会对他进行解密壳程序&#xff0c;来直接运行可执行的文件&#xff0c;当然苹果这样做的目…

骚操作“破解“App

mitmproxy就是用于MITM的proxy&#xff0c;MITM即中间人攻击&#xff08;Man-in-the-middle attack&#xff09;。用于中间人攻击的代理首先会向正常的代理一样转发请求&#xff0c;保障服务端与客户端的通信&#xff0c;其次会实时查、记录其截获的数据或篡改数据&#xff0c;…

逻辑回归算法实现

逻辑回归算法原理还是比较容易理解的&#xff0c;根据计算的结果实现一下&#xff1a; 手写的推导过程如下&#xff1a; 然后我们开始写实现的过程 1、写出判断模型准确性的函数&#xff0c;这个比较容易理解 import numpy as np from math import sqrtdef accuracy_score(y…

逻辑回归算法 - 乳腺癌预测

1 目标 根据历史女性乳腺癌患者数据集&#xff08;医学指标&#xff09;构建逻辑回归分类模型进行良&#xff0f;恶性乳腺癌肿瘤预测 2 数据集 2.1 数据集来源 数据集源于威斯康星州临床科学中心。每个记录代表一个乳腺癌的随访数据样本。这些是DR Wolberg自1984~1995随访搜…

以《简单易懂》的语言带你搞懂逻辑回归算法【附Python代码详解】机器学习系列之逻辑回归篇

大家早上好&#xff0c;本人姓吴&#xff0c;如果觉得文章写得还行的话也可以叫我吴老师。欢迎大家跟我一起走进数据分析的世界&#xff0c;一起学习&#xff01; 感兴趣的朋友可以关注我或者我的数据分析专栏&#xff0c;里面有许多优质的文章跟大家分享哦。 目录 必看前言逻辑…

逻辑回归算法梳理(从理论到示例)

逻辑回归算法的名字里虽然带有“回归”二字&#xff0c;但实际上逻辑回归算法是用来解决分类问题的算法。线性回归和逻辑回归相当于一对“孪生兄弟”&#xff0c;本文将从二分类入手&#xff0c;介绍逻辑回归算法的预测函数、损失函数&#xff08;成本函数&#xff09;和梯度下…

机器学习 逻辑回归算法应用案例

机器学习 逻辑回归算法应用案例 时间&#xff1a;2020.09.12 出处&#xff1a;https://www.kesci.com/home/project/5bfe39b3954d6e0010681cd1 注明&#xff1a;初学逻辑回归&#xff0c;跟着博客大佬文章过了一遍&#xff0c;自己留个记录以便之后翻阅&#xff0c;也供大家学…

机器学习——逻辑回归算法代码实现

机器学习——逻辑回归算法代码实现 前言一、逻辑回归是什么&#xff1f;二、代码实现1.数据说明2.逻辑回归代码 前言 最近准备开始学习机器学习&#xff0c;后续将对学习内容进行记录&#xff0c;该文主要针对逻辑回归代码实现进行记录&#xff01; 一、逻辑回归是什么&#x…

逻辑回归算法的优化

一:有无截距: 如上图。可以知道,有截距的线条数比无截距的线条数(过原点的线条)要多。所以在选择逻辑回归的时候,通常要设置截距。增加正确的概率。 代码: val lr = new LogisticRegressionWithSGD() ----创建逻辑回归对象 l…

Python机器学习--回归算法--逻辑回归算法

逻辑回归算法 逻辑回归算法类型: 逻辑回归属于有监督学习的分类算法&#xff08;只能做二分类&#xff09; 逻辑回归算法原理: 将线性回归的结果输入sigmoid函数中&#xff0c;得出预测为类1的概率&#xff08; 如果概率为0.2 有20%的可能属于类1&#xff0c;属于类0的概率…

算法笔记(11)逻辑回归算法及Python代码实现

逻辑回归算法是一种被广泛使用的分类算法&#xff0c;通过训练数据中的正负样本&#xff0c;学习样本特征到样本标签之间的假设函数。逻辑回归假设因变量 y 服从伯努利分布&#xff0c;而线性回归假设因变量 y 服从高斯分布。 因此与线性回归有很多相同之处&#xff0c;去除Sig…

深度学习原理-----逻辑回归算法

系列文章目录 深度学习原理-----线性回归梯度下降法 深度学习原理-----逻辑回归算法 深度学习原理-----全连接神经网络 深度学习原理-----卷积神经网络 深度学习原理-----循环神经网络&#xff08;RNN、LSTM&#xff09; 时间序列预测-----基于BP、LSTM、CNN-LSTM神经网络…

逻辑回归算法原理及python实现

文章目录 引言逻辑回归算法原理逻辑回归损失函数 python实现逻辑回归决策边界python实现多项式逻辑回归sklearn中的逻辑回归逻辑回归中的正则化sklearn实现逻辑回归 引言 逻辑回归&#xff08;Logistic Regression&#xff09;是一种分类学习算法&#xff0c;其本质是将样本的…

基于逻辑回归算法模型搭建思路

在真实工作场景中&#xff0c;有多种算法依据借贷数据集建立模型&#xff0c;主要使用的算法有逻辑回归、神经网络、决策树、贝叶斯信念网、GBDT算法等&#xff0c;本系列文章旨在为刚入门和对模型感兴趣的同学介绍传统风控模型算法之一——逻辑回归。 前方高能&#xff01;准…

【机器学习】Logistic Regression 逻辑回归算法详解 + Java代码实现

文章目录 一、逻辑回归简介1.1 什么是逻辑回归1.2 Sigmoid函数1.3 预测函数 二、逻辑回归实战 - Java代码实现 一、逻辑回归简介 1.1 什么是逻辑回归 逻辑回归&#xff08;Logistic Regression&#xff09;是一种用于解决二分类&#xff08;0 or 1&#xff09;问题的机器学习…

机器学习之逻辑回归算法

文章目录 逻辑回归原理推导逻辑回归求解 逻辑回归&#xff08;Logistic Regression&#xff09;是机器学习中的一种分类模型&#xff0c;它是一种分类算法&#xff0c;虽然名字中带有回归&#xff0c;但是它与回归之间有一定的联系。 看到回归二字&#xff0c;很多人可能会认为…

机器学习算法 之 逻辑回归算法

1 逻辑回归之第一次学习 本文内容主要转自两处&#xff1a; [1] 逻辑回归从入门到深入&#xff08;logistic regression) 本文内容从Python 逻辑回归实际使用的角度出发&#xff0c;较为通俗易懂&#xff0c;感谢其作者的分享。 [2] 《百面机器学习》之逻辑回归 注意&#xf…