2018年4月

如果恶意软件或其情况改变了你的文件系统,Linux 完整性检查工具会提示你。

尽管 Linux 被认为是最安全的操作系统(排在 Windows 和 MacOS 之前),但它仍然容易受到 rootkit 和其他恶意软件的影响。因此,Linux 用户需要知道如何保护他们的服务器或个人电脑免遭破坏,他们需要采取的第一步就是保护文件系统。

在本文中,我们将看看 Tripwire,这是保护 Linux 文件系统的绝佳工具。Tripwire 是一个完整性检查工具,使得系统管理员、安全工程师和其他人能够检测系统文件的变更。虽然它不是唯一的选择(AIDESamhain 提供类似功能),但 Tripwire 可以说是 Linux 系统文件中最常用的完整性检查程序,并在 GPLv2 许可证下开源。

Tripwire 如何工作

了解 Tripwire 如何运行对了解 Tripwire 在安装后会做什么有所帮助。Tripwire 主要由两个部分组成:策略和数据库。策略列出了完整性检查器应该生成快照的所有文件和目录,还创建了用于识别对目录和文件更改违规的规则。数据库由 Tripwire 生成的快照组成。

Tripwire 还有一个配置文件,它指定数据库、策略文件和 Tripwire 可执行文件的位置。它还提供两个加密密钥 —— 站点密钥和本地密钥 —— 以保护重要文件免遭篡改。站点密钥保护策略和配置文件,而本地密钥保护数据库和生成的报告。

Tripwire 会定期将目录和文件与数据库中的快照进行比较并报告所有的更改。

安装 Tripwire

要 Tripwire,我们需要先下载并安装它。Tripwire 适用于几乎所有的 Linux 发行版。你可以从 Sourceforge 下载一个开源版本,并如下根据你的 Linux 版本进行安装。

Debian 和 Ubuntu 用户可以使用 apt-get 直接从仓库安装 Tripwire。非 root 用户应该输入 sudo 命令通过 apt-get 安装 Tripwire。

sudo apt-get update
sudo  apt-get install tripwire  

CentOS 和其他基于 RPM 的发行版使用类似的过程。为了最佳实践,请在安装新软件包(如 Tripwire)之前更新仓库。命令 yum install epel-release 意思是我们想要安装额外的存储库。 (epel 代表 Extra Packages for Enterprise Linux。)

yum update
yum install epel-release
yum install tripwire  

此命令会在安装中运行让 Tripwire 有效运行所需的配置。另外,它会在安装过程中询问你是否使用密码。你可以两个选择都选择 “Yes”。

另外,如果需要构建配置文件,请选择 “Yes”。选择并确认站点密钥和本地密钥的密码。(建议使用复杂的密码,例如 Il0ve0pens0urce 这样的。)

建立并初始化 Tripwire 数据库

接下来,按照以下步骤初始化 Tripwire 数据库:

tripwire --init

你需要提供本地密钥密码才能运行这些命令。

使用 Tripwire 进行基本的完整性检查

你可以使用以下命令让 Tripwire 检查你的文件或目录是否已被修改。Tripwire 将文件和目录与数据库中的初始快照进行比较的能力依赖于你在活动策略中创建的规则。

tripwire  --check  

你还可以将 -check 命令限制为特定的文件或目录,如下所示:

tripwire   --check   /usr/tmp  

另外,如果你需要使用 Tripwire 的 -check 命令的更多帮助,该命令能够查阅 Tripwire 的手册:

tripwire  --check  --help  

使用 Tripwire 生成报告

要轻松生成每日系统完整性报告,请使用以下命令创建一个 crontab 任务:

crontab -e

之后,你可以编辑此文件(使用你选择的文本编辑器)来引入由 cron 运行的任务。例如,你可以使用以下命令设置一个 cron 任务,在每天的 5:40 将 Tripwire 的报告发送到你的邮箱:

40 5  *  *  *  usr/sbin/tripwire   --check

无论你决定使用 Tripwire 还是其他具有类似功能的完整性检查程序,关键问题都是确保你有解决方案来保护 Linux 文件系统的安全。


via: https://opensource.com/article/18/1/securing-linux-filesystem-tripwire

作者:Michael Kwaku Aboagye 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

有时候你很忙。而有时候你只是需要看起来很忙,就像电影中的黑客一样。有一些开源工具就是干这个的。

如果在你在消磨时光时看过谍战片、动作片或犯罪片,那么你就会清晰地在脑海中勾勒出黑客的电脑屏幕的样子。就像是在《黑客帝国》电影中,代码雨 一样的十六进制数字流,又或是一排排快速移动的代码。

也许电影中出现一幅世界地图,其中布满了闪烁的光点和一些快速更新的图表。不可或缺的,也可能有 3D 旋转的几何形状。甚至,这一切都会显示在一些完全不符合人类习惯的数量荒谬的显示屏上。 在《剑鱼行动》电影中黑客就使用了七个显示屏。

当然,我们这些从事计算机行业的人一下子就明白这完全是胡说八道。虽然在我们中,许多人都有双显示器(或更多),但一个闪烁的数据仪表盘、刷新的数据通常和专注工作是相互矛盾的。编写代码、项目管理和系统管理与日常工作不同。我们遇到的大多数情况,为了解决问题,都需要大量的思考,与客户沟通所得到一些研究和组织的资料,然后才是少许的 敲代码

然而,这与我们想追求电影中的效果并不矛盾,也许,我们只是想要看起来“忙于工作”而已。

注:当然,我仅仅是在此胡诌。如果您公司实际上是根据您繁忙程度来评估您的工作时,无论您是蓝领还是白领,都需要亟待解决这样的工作文化。假装工作很忙是一种有毒的文化,对公司和员工都有害无益。

这就是说,让我们找些乐子,用一些老式的、毫无意义的数据和代码片段填充我们的屏幕。(当然,数据或许有意义,但不是在这种没有上下文的环境中。)当然有一些用于此用途的有趣的图形界面程序,如 hackertyper.net 或是 GEEKtyper.com 网站(LCTT 译注:是在线假装黑客操作的网站),为什么不使用标准的 Linux 终端程序呢?对于更老派的外观,可以考虑使用 酷炫复古终端,这听起来确实如此:一个酷炫的复古终端程序。我将在下面的屏幕截图中使用酷炫复古终端,因为它看起来的确很酷。

Genact

我们来看下第一个工具——Genact。Genact 的原理很简单,就是慢慢地无尽循环播放您选择的一个序列,让您的代码在您外出休息时“编译”。由您来决定播放顺序,但是其中默认包含数字货币挖矿模拟器、Composer PHP 依赖关系管理工具、内核编译器、下载器、内存转储等工具。其中我最喜欢的是其中类似《模拟城市》加载显示。所以只要没有人仔细检查,你可以花一整个下午等待您的电脑完成进度条。

Genact 发布了 支持 Linux、OS X 和 Windows 的版本。并且其 Rust 源代码 在 GitHub 上开源(遵循 MIT 许可证)。

Hollywood

Hollywood 采取更直接的方法。它本质上是在终端中创建一个随机的数量和配置的分屏,并启动那些看起来很繁忙的应用程序,如 htop、目录树、源代码文件等,并每隔几秒将其切换。它被组织成一个 shell 脚本,所以可以非常容易地根据需求进行修改。

Hollywood的 源代码 在 GitHub 上开源(遵循 Apache 2.0 许可证)。

Blessed-contrib

Blessed-contrib 是我个人最喜欢的应用,实际上并不是为了这种表演而专门设计的应用。相反地,它是一个基于 Node.js 的终端仪表盘的构建库的演示文件。与其他两个不同,实际上我已经在工作中使用 Blessed-contrib 的库,而不是用于假装忙于工作。因为它是一个相当有用的库,并且可以使用一组在命令行显示信息的小部件。与此同时填充虚拟数据也很容易,所以可以很容易实现你在计算机上模拟《战争游戏》的想法。

Blessed-contrib 的源代码在 GitHub 上(遵循 MIT 许可证)。

当然,尽管这些工具很容易使用,但也有很多其他的方式使你的屏幕丰富。在你看到电影中最常用的工具之一就是Nmap,这是一个开源的网络安全扫描工具。实际上,它被广泛用作展示好莱坞电影中,黑客电脑屏幕上的工具。因此 Nmap 的开发者创建了一个 页面,列出了它出现在其中的一些电影,从《黑客帝国 2:重装上阵》到《谍影重重3》、《龙纹身的女孩》,甚至《虎胆龙威 4》。

当然,您可以创建自己的组合,使用终端多路复用器(如 screentmux)启动您希望使用的任何数据切分程序。

那么,您是如何使用您的屏幕的呢?


via: https://opensource.com/article/18/2/command-line-tools-productivity

作者:Jason Baker 译者:wyxplus 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

不久前,我们介绍了一个名为 “Betty” 的命令行虚拟助手。今天,我偶然发现了一个类似的实用程序,叫做 “Yoda”。Yoda 是一个命令行个人助理,可以帮助您在 Linux 中完成一些琐碎的任务。它是用 Python 编写的一个自由开源应用程序。在本指南中,我们将了解如何在 GNU/Linux 中安装和使用 Yoda。

安装 Yoda,命令行私人助理。

Yoda 需要 Python 2 和 PIP 。如果在您的 Linux 中没有安装 PIP,请参考下面的指南来安装它。只要确保已经安装了 python2-pip 。Yoda 可能不支持 Python 3。

注意:我建议你在 Python 虚拟环境下试用 Yoda。 不仅仅是 Yoda,应该总在虚拟环境中尝试任何 Python 应用程序,让它们不会干扰全局安装的软件包。 您可以按照上文链接中标题为“创建虚拟环境”一节中所述设置虚拟环境。

在您的系统上安装了 pip 之后,使用下面的命令克隆 Yoda 库。

$ git clone https://github.com/yoda-pa/yoda

上面的命令将在当前工作目录中创建一个名为 yoda 的目录,并在其中克隆所有内容。转到 yoda 目录:

$ cd yoda/

运行以下命令安装 Yoda 应用程序。

$ pip install .

请注意最后的点(.)。 现在,所有必需的软件包将被下载并安装。

配置 Yoda

首先,设置配置以将您的信息保存在本地系统上。

运行下面的命令:

$ yoda setup new

填写下列的问题:

Enter your name:
Senthil Kumar
What's your email id?
[email protected]
What's your github username?
sk
Enter your github password:
Password:
Where shall your config be stored? (Default: ~/.yoda/)

A configuration file already exists. Are you sure you want to overwrite it? (y/n)
y

你的密码在加密后保存在配置文件中,所以不用担心。

要检查当前配置,请运行:

$ yoda setup check

你会看到如下的输出。

Name: Senthil Kumar
Email: [email protected]
Github username: sk

默认情况下,您的信息存储在 ~/.yoda 目录中。

要删除现有配置,请执行以下操作:

$ yoda setup delete

用法

Yoda 包含一个简单的聊天机器人。您可以使用下面的聊天命令与它交互。

$ yoda chat who are you

样例输出:

Yoda speaks:
I'm a virtual agent

$ yoda chat how are you
Yoda speaks:
I'm doing very well. Thanks!

以下是我们可以用 Yoda 做的事情:

测试网络速度

让我们问一下 Yoda 关于互联网速度的问题。运行:

$ yoda speedtest
Speed test results:
Ping: 108.45 ms
Download: 0.75 Mb/s
Upload: 1.95 Mb/s

缩短和展开网址

Yoda 还有助于缩短任何网址:

$ yoda url shorten https://www.ostechnix.com/
Here's your shortened URL:
https://goo.gl/hVW6U0

要展开缩短的网址:

$ yoda url expand https://goo.gl/hVW6U0
Here's your original URL:
https://www.ostechnix.com/

阅读 Hacker News

我是 Hacker News 网站的常客。 如果你像我一样,你可以使用 Yoda 从下面的 Hacker News 网站阅读新闻。

$ yoda hackernews
News-- 1/513

Title-- Show HN: a Yelp for iOS developers
Description-- I came up with this idea "a Yelp for developers" when talking with my colleagues. My hypothesis is that, it would be very helpful if we know more about a library before choosing to use it. It's similar to that we want to know more about a restaurant by checki…
url-- https://news.ycombinator.com/item?id=16636071

Continue? [press-"y"]

Yoda 将一次显示一个项目。 要阅读下一条新闻,只需输入 y 并按下回车。

管理个人日记

我们也可以保留个人日记以记录重要事件。

使用命令创建一个新的日记:

$ yoda diary nn
Input your entry for note:
Today I learned about Yoda

要创建新笔记,请再次运行上述命令。

查看所有笔记:

$ yoda diary notes
Today's notes:
----------------
 Time | Note
--------|-----
16:41:41| Today I learned about Yoda

不仅仅是笔记,Yoda 还可以帮助你创建任务。

要创建新任务,请运行:

$ yoda diary nt
Input your entry for task:
Write an article about Yoda and publish it on OSTechNix

要查看任务列表,请运行:

$ yoda diary tasks
Today's agenda:
----------------
Status | Time | Text
-------|---------|-----
 O | 16:44:03: Write an article about Yoda and publish it on OSTechNix
----------------

Summary:
----------------
Incomplete tasks: 1
Completed tasks: 0

正如你在上面看到的,我有一个未完成的任务。 要将其标记为已完成,请运行以下命令并输入已完成的任务序列号并按下回车键:

$ yoda diary ct
Today's agenda:
----------------
Number | Time | Task
-------|---------|-----
 1 | 16:44:03: Write an article about Yoda and publish it on OSTechNix
Enter the task number that you would like to set as completed
1

您可以随时使用命令分析当前月份的任务:

$ yoda diary analyze
Percentage of incomplete task : 0
Percentage of complete task : 100
Frequency of adding task (Task/Day) : 3

有时候,你可能想要记录一个关于你爱的或者敬佩的人的个人资料。

记录关于爱人的笔记

首先,您需要设置配置来存储朋友的详细信息。 请运行:

$ yoda love setup

输入你的朋友的详细信息:

Enter their name:
Abdul Kalam
Enter sex(M/F):
M
Where do they live?
Rameswaram

要查看此人的详细信息,请运行:

$ yoda love status
{'place': 'Rameswaram', 'name': 'Abdul Kalam', 'sex': 'M'}

要添加你的爱人的生日:

$ yoda love addbirth
Enter birthday
15-10-1931

查看生日:

$ yoda love showbirth
Birthday is 15-10-1931

你甚至可以添加关于该人的笔记:

$ yoda love note
Avul Pakir Jainulabdeen Abdul Kalam better known as A. P. J. Abdul Kalam, was the 11th President of India from 2002 to 2007.

您可以使用命令查看笔记:

$ yoda love notes
Notes:
1: Avul Pakir Jainulabdeen Abdul Kalam better known as A. P. J. Abdul Kalam, was the 11th President of India from 2002 to 2007.

你也可以写下这个人喜欢的东西:

$ yoda love like
Add things they like
Physics, Aerospace
Want to add more things they like? [y/n]
n

要查看他们喜欢的东西,请运行:

$ yoda love likes
Likes:
1: Physics, Aerospace

跟踪资金费用

您不需要单独的工具来维护您的财务支出。 Yoda 会替您处理好。

首先,使用命令设置您的金钱支出配置:

$ yoda money setup

输入您的货币代码和初始金额:

Enter default currency code:
INR
{u'USD': 0.015338, u'IDR': 211.06, u'BGN': 0.024436, u'ISK': 1.5305, u'ILS': 0.053402, u'GBP': 0.010959, u'DKK': 0.093063, u'CAD': 0.020041, u'MXN': 0.28748, u'HUF': 3.8873, u'RON': 0.058302, u'MYR': 0.060086, u'SEK': 0.12564, u'SGD': 0.020208, u'HKD': 0.12031, u'AUD': 0.019908, u'CHF': 0.014644, u'KRW': 16.429, u'CNY': 0.097135, u'TRY': 0.06027, u'HRK': 0.092986, u'NZD': 0.021289, u'THB': 0.47854, u'EUR': 0.012494, u'NOK': 0.11852, u'RUB': 0.88518, u'JPY': 1.6332, u'CZK': 0.31764, u'BRL': 0.050489, u'PLN': 0.052822, u'PHP': 0.79871, u'ZAR': 0.1834}
₹
Indian rupee
Enter initial amount:
10000

要查看金钱配置,只需运行:

$ yoda money status
{'initial_money': 10000, 'currency_code': 'INR'}

让我们假设你买了一本价值 250 卢比的书。 要添加此费用,请运行:

$ yoda money exp
Spend 250 INR on books
output:

要查看花费,请运行:

$ yoda money exps
2018-03-21 17:12:31 INR 250 books

创建想法列表

创建一个新的想法:

$ yoda ideas add --task <task_name> --inside <project_name>

列出想法:

$ yoda ideas show

从任务中移除一个想法:

$ yoda ideas remove --task <task_name> --inside <project_name>

要完全删除这个想法,请运行:

$ yoda ideas remove --project <project_name>

学习英语词汇

Yoda 帮助你学习随机英语单词并追踪你的学习进度。

要学习一个新单词,请输入:

$ yoda vocabulary word

它会随机显示一个单词。 按回车键显示单词的含义。 再一次,Yoda 问你是否已经知道这个词的意思。 如果您已经知道,请输入“是”。 如果您不知道,请输入“否”。 这可以帮助你跟踪你的进度。 使用以下命令来了解您的进度。

$ yoda vocabulary accuracy

此外,Yoda 可以帮助您做其他一些事情,比如找到单词的定义和创建插卡以轻松学习任何内容。 有关更多详细信息和可用选项列表,请参阅帮助部分。

$ yoda --help

更多好的东西来了。请继续关注!

干杯!


via: https://www.ostechnix.com/yoda-the-command-line-personal-assistant-for-your-linux-system/

作者:SK 译者:amwps290 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

最大化你的项目影响。

科学社区正在加速拥抱 自由及开源硬件 Free and Open Source Hardware FOSH)。 研究员正忙于改进他们自己的装备并创造数以百计的基于分布式数字制造模型的设备来推动他们的研究。

热衷于 FOSH 的主要原因还是钱: 有研究表明,和专用设备相比,FOSH 可以节省 90% 到 99% 的花费。基于开源硬件商业模式的科学 FOSH 的商业化已经推动其快速地发展为一个新的工程领域,并为此定期举行 GOSH 年会

特别的是,不止一本,而是关于这个主题的[两本学术期刊]:[Journal of Open Hardware] (由 Ubiquity 出版,一个新的自由访问出版商,同时出版了 Journal of Open Research Software )以及 HardwareX(由 Elsevier 出版的一种自由访问期刊,它是世界上最大的学术出版商之一)。

由于学术社区的支持,科学 FOSH 的开发者在获取制作乐趣并推进科学快速发展的同时获得学术声望。

科学 FOSH 的5个步骤

Shane Oberloier 和我在名为 Designs 的自由访问工程期刊上共同发表了一篇关于设计 FOSH 科学设备原则的文章。我们以滑动式烘干机为例,制造成本低于 20 美元,仅是专用设备价格的三百分之一。科学医疗设备往往比较复杂,开发 FOSH 替代品将带来巨大的回报。

我总结了 5 个步骤(包括 6 条设计原则),它们在 Shane Oberloier 和我发表的文章里有详细阐述。这些设计原则也可以推广到非科学设备,而且制作越复杂的设计越能带来更大的潜在收益。

如果你对科学项目的开源硬件设计感兴趣,这些步骤将使你的项目的影响最大化。

  1. 评估类似现有工具的功能,你的 FOSH 设计目标应该针对实际效果而不是现有的设计(LCTT 译注:作者的意思应该是不要被现有设计缚住手脚)。必要的时候需进行概念证明。
  2. 使用下列设计原则:

    • 在设备生产中,仅使用自由和开源的软件工具链(比如,开源的 CAD 工具,例如 OpenSCADFreeCADBlender)和开源硬件。
    • 尝试减少部件的数量和类型并降低工具的复杂度
    • 减少材料的数量和制造成本。
    • 尽量使用能够分发的部件或使用方便易得的工具(比如 RepRap 3D 打印机)进行部件的数字化生产。
    • 对部件进行参数化设计,这使他人可以对你的设计进行个性化改动。相较于特例化设计,参数化设计会更有用。在未来的项目中,使用者可以通过修改核心参数来继续利用它们。
    • 所有不能使用现有的开源硬件以分布式的方式轻松且经济地制造的零件,必须选择现货产品以方便采购。
  3. 验证功能设计。
  4. 提供关于设计、生产、装配、校准和操作的详尽设备文档。包括原始设计文件而不仅仅是用于生产的。 开源硬件协会 Open Source Hardware Association 对于开源设计的发布和文档化有额外的指南,总结如下:

    • 以通用的形式分享设计文件。
    • 提供详尽的材料清单,包括价格和采购信息。
    • 如果涉及软件,确保代码对大众来说清晰易懂。
    • 作为生产时的参考,必须提供足够的照片,以确保没有任何被遮挡的部分。
    • 在描述方法的章节,整个制作过程必须被细化成简单步骤以便复制此设计。
    • 在线上分享并指定许可证。这为用户提供了合理使用该设计的信息。
  5. 主动分享!为了使 FOSH 发扬光大,设计必须被广泛、频繁和有效地分享以提升它们的存在感。所有的文档应该在自由访问文献中发表,并与适当的社区共享。 开源科学框架 Open Science Framework 是一个值得考虑的优雅的通用存储库,它由 开源科学中心 Center for Open Science 主办,该中心设置为接受任何类型的文件并处理大型数据集。

这篇文章得到了 Fulbright Finland 的支持,该公司赞助了芬兰 Fulbright-Aalto 大学的特聘校席 Joshua Pearce 在开源科学硬件方面的研究工作。


via: https://opensource.com/article/18/2/5-steps-creating-successful-open-hardware

作者:Joshua Pearce 译者:kennethXia 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

(之前的 gdb 系列文章:gdb 如何工作(2016)三步上手 gdb(2014)

在这周,我发现我可以从 gdb 上调用 C 函数。这看起来很酷,因为在过去我认为 gdb 最多只是一个只读调试工具。

我对 gdb 能够调用函数感到很吃惊。正如往常所做的那样,我在 Twitter 上询问这是如何工作的。我得到了大量的有用答案。我最喜欢的答案是 Evan Klitzke 的示例 C 代码,它展示了 gdb 如何调用函数。代码能够运行,这很令人激动!

我(通过一些跟踪和实验)认为那个示例 C 代码和 gdb 实际上如何调用函数不同。因此,在这篇文章中,我将会阐述 gdb 是如何调用函数的,以及我是如何知道的。

关于 gdb 如何调用函数,还有许多我不知道的事情,并且,在这儿我写的内容有可能是错误的。

从 gdb 中调用 C 函数意味着什么?

在开始讲解这是如何工作之前,我先快速的谈论一下我是如何发现这件令人惊讶的事情的。

假如,你已经在运行一个 C 程序(目标程序)。你可以运行程序中的一个函数,只需要像下面这样做:

  • 暂停程序(因为它已经在运行中)
  • 找到你想调用的函数的地址(使用符号表)
  • 使程序(目标程序)跳转到那个地址
  • 当函数返回时,恢复之前的指令指针和寄存器

通过符号表来找到想要调用的函数的地址非常容易。下面是一段非常简单但能够工作的代码,我在 Linux 上使用这段代码作为例子来讲解如何找到地址。这段代码使用 elf crate。如果我想找到 PID 为 2345 的进程中的 foo 函数的地址,那么我可以运行 elf_symbol_value("/proc/2345/exe", "foo")

fn elf_symbol_value(file_name: &str, symbol_name: &str) -> Result<u64, Box<std::error::Error>> {
    // 打开 ELF 文件 
    let file = elf::File::open_path(file_name).ok().ok_or("parse error")?;
    // 在所有的段 & 符号中循环,直到找到正确的那个
    let sections = &file.sections;
    for s in sections {
        for sym in file.get_symbols(&s).ok().ok_or("parse error")? {
            if sym.name == symbol_name {
                return Ok(sym.value);
            }
        }
    }
    None.ok_or("No symbol found")?
}

这并不能够真的发挥作用,你还需要找到文件的内存映射,并将符号偏移量加到文件映射的起始位置。找到内存映射并不困难,它位于 /proc/PID/maps 中。

总之,找到想要调用的函数地址对我来说很直接,但是其余部分(改变指令指针,恢复寄存器等)看起来就不这么明显了。

你不能仅仅进行跳转

我已经说过,你不能够仅仅找到你想要运行的那个函数地址,然后跳转到那儿。我在 gdb 中尝试过那样做(jump foo),然后程序出现了段错误。毫无意义。

如何从 gdb 中调用 C 函数

首先,这是可能的。我写了一个非常简洁的 C 程序,它所做的事只有 sleep 1000 秒,把这个文件命名为 test.c

#include <unistd.h>

int foo() {
    return 3;
}
int main() {
    sleep(1000);
}

接下来,编译并运行它:

$ gcc -o test  test.c
$ ./test

最后,我们使用 gdb 来跟踪 test 这一程序:

$ sudo gdb -p $(pgrep -f test)
(gdb) p foo()
$1 = 3
(gdb) quit

我运行 p foo() 然后它运行了这个函数!这非常有趣。

这有什么用?

下面是一些可能的用途:

  • 它使得你可以把 gdb 当成一个 C 应答式程序(REPL),这很有趣,我想对开发也会有用
  • 在 gdb 中进行调试的时候展示/浏览复杂数据结构的功能函数(感谢 @invalidop
  • 在进程运行时设置一个任意的名字空间(我的同事 nelhage 对此非常惊讶)
  • 可能还有许多我所不知道的用途

它是如何工作的

当我在 Twitter 上询问从 gdb 中调用函数是如何工作的时,我得到了大量有用的回答。许多答案是“你从符号表中得到了函数的地址”,但这并不是完整的答案。

有个人告诉了我两篇关于 gdb 如何工作的系列文章:原生调试:第一部分原生调试:第二部分。第一部分讲述了 gdb 是如何调用函数的(指出了 gdb 实际上完成这件事并不简单,但是我将会尽力)。

步骤列举如下:

  1. 停止进程
  2. 创建一个新的栈框(远离真实栈)
  3. 保存所有寄存器
  4. 设置你想要调用的函数的寄存器参数
  5. 设置栈指针指向新的 栈框 stack frame
  6. 在内存中某个位置放置一条陷阱指令
  7. 为陷阱指令设置返回地址
  8. 设置指令寄存器的值为你想要调用的函数地址
  9. 再次运行进程!

(LCTT 译注:如果将这个调用的函数看成一个单独的线程,gdb 实际上所做的事情就是一个简单的线程上下文切换)

我不知道 gdb 是如何完成这些所有事情的,但是今天晚上,我学到了这些所有事情中的其中几件。

创建一个栈框

如果你想要运行一个 C 函数,那么你需要一个栈来存储变量。你肯定不想继续使用当前的栈。准确来说,在 gdb 调用函数之前(通过设置函数指针并跳转),它需要设置栈指针到某个地方。

这儿是 Twitter 上一些关于它如何工作的猜测:

我认为它在当前栈的栈顶上构造了一个新的栈框来进行调用!

以及

你确定是这样吗?它应该是分配一个伪栈,然后临时将 sp (栈指针寄存器)的值改为那个栈的地址。你可以试一试,你可以在那儿设置一个断点,然后看一看栈指针寄存器的值,它是否和当前程序寄存器的值相近?

我通过 gdb 做了一个试验:

(gdb) p $rsp
$7 = (void *) 0x7ffea3d0bca8
(gdb) break foo
Breakpoint 1 at 0x40052a
(gdb) p foo()
Breakpoint 1, 0x000000000040052a in foo ()
(gdb) p $rsp
$8 = (void *) 0x7ffea3d0bc00

这看起来符合“gdb 在当前栈的栈顶构造了一个新的栈框”这一理论。因为栈指针($rsp)从 0x7ffea3d0bca8 变成了 0x7ffea3d0bc00 —— 栈指针从高地址往低地址长。所以 0x7ffea3d0bca80x7ffea3d0bc00 的后面。真是有趣!

所以,看起来 gdb 只是在当前栈所在位置创建了一个新的栈框。这令我很惊讶!

改变指令指针

让我们来看一看 gdb 是如何改变指令指针的!

(gdb) p $rip
$1 = (void (*)()) 0x7fae7d29a2f0 <__nanosleep_nocancel+7>
(gdb) b foo
Breakpoint 1 at 0x40052a
(gdb) p foo()
Breakpoint 1, 0x000000000040052a in foo ()
(gdb) p $rip
$3 = (void (*)()) 0x40052a <foo+4>

的确是!指令指针从 0x7fae7d29a2f0 变为了 0x40052afoo 函数的地址)。

我盯着输出看了很久,但仍然不理解它是如何改变指令指针的,但这并不影响什么。

如何设置断点

上面我写到 break foo 。我跟踪 gdb 运行程序的过程,但是没有任何发现。

下面是 gdb 用来设置断点的一些系统调用。它们非常简单。它把一条指令用 cc 代替了(这告诉我们 int3 意味着 send SIGTRAP https://defuse.ca/online-x86-assembler.html),并且一旦程序被打断了,它就把指令恢复为原先的样子。

我在函数 foo 那儿设置了一个断点,地址为 0x400528

PTRACE_POKEDATA 展示了 gdb 如何改变正在运行的程序。

// 改变 0x400528 处的指令
25622 ptrace(PTRACE_PEEKTEXT, 25618, 0x400528, [0x5d00000003b8e589]) = 0
25622 ptrace(PTRACE_POKEDATA, 25618, 0x400528, 0x5d00000003cce589) = 0
// 开始运行程序
25622 ptrace(PTRACE_CONT, 25618, 0x1, SIG_0) = 0
// 当到达断点时获取一个信号
25622 ptrace(PTRACE_GETSIGINFO, 25618, NULL, {si_signo=SIGTRAP, si_code=SI_KERNEL, si_value={int=-1447215360, ptr=0x7ffda9bd3f00}}) = 0
// 将 0x400528 处的指令更改为之前的样子
25622 ptrace(PTRACE_PEEKTEXT, 25618, 0x400528, [0x5d00000003cce589]) = 0
25622 ptrace(PTRACE_POKEDATA, 25618, 0x400528, 0x5d00000003b8e589) = 0

在某处放置一条陷阱指令

当 gdb 运行一个函数的时候,它也会在某个地方放置一条陷阱指令。这是其中一条。它基本上是用 cc 来替换一条指令(int3)。

5908  ptrace(PTRACE_PEEKTEXT, 5810, 0x7f6fa7c0b260, [0x48f389fd89485355]) = 0
5908  ptrace(PTRACE_PEEKTEXT, 5810, 0x7f6fa7c0b260, [0x48f389fd89485355]) = 0
5908 ptrace(PTRACE_POKEDATA, 5810, 0x7f6fa7c0b260, 0x48f389fd894853cc) = 0

0x7f6fa7c0b260 是什么?我查看了进程的内存映射,发现它位于 /lib/x86_64-linux-gnu/libc-2.23.so 中的某个位置。这很奇怪,为什么 gdb 将陷阱指令放在 libc 中?

让我们看一看里面的函数是什么,它是 __libc_siglongjmp 。其他 gdb 放置陷阱指令的地方的函数是 __longjmp___longjmp_chkdl_main_dl_close_worker

为什么?我不知道!也许出于某种原因,当函数 foo() 返回时,它调用 longjmp ,从而 gdb 能够进行返回控制。我不确定。

gdb 如何调用函数是很复杂的!

我将要在这儿停止了(现在已经凌晨 1 点),但是我知道的多一些了!

看起来“gdb 如何调用函数”这一问题的答案并不简单。我发现这很有趣并且努力找出其中一些答案,希望你也能够找到。

我依旧有很多未回答的问题,关于 gdb 是如何完成这些所有事的,但是可以了。我不需要真的知道关于 gdb 是如何工作的所有细节,但是我很开心,我有了一些进一步的理解。


via: https://jvns.ca/blog/2018/01/04/how-does-gdb-call-functions/

作者:Julia Evans 译者:ucasFL 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

如果你加入了一家新公司,要为开发团队安装所需的软件并重启服务,这个时候首先要弄清楚它们运行在什么发行版以及哪个版本的系统上,你才能正确完成后续的工作。作为系统管理员,充分了解系统信息是首要的任务。

查看 Linux 发行版名称和版本号有很多种方法。你可能会问,为什么要去了解这些基本信息呢?

因为对于诸如 RHEL、Debian、openSUSE、Arch Linux 这几种主流发行版来说,它们各自拥有不同的包管理器来管理系统上的软件包,如果不知道所使用的是哪一个发行版的系统,在软件包安装的时候就会无从下手,而且由于大多数发行版都是用 systemd 命令而不是 SysVinit 脚本,在重启服务的时候也难以执行正确的命令。

下面来看看可以使用那些基本命令来查看 Linux 发行版名称和版本号。

方法总览

  • lsb_release 命令
  • /etc/*-release 文件
  • uname 命令
  • /proc/version 文件
  • dmesg 命令
  • YUM 或 DNF 命令
  • RPM 命令
  • APT-GET 命令

方法 1: lsb\_release 命令

LSB( Linux 标准库 Linux Standard Base )能够打印发行版的具体信息,包括发行版名称、版本号、代号等。

# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.3 LTS
Release: 16.04
Codename: xenial

方法 2: /etc/*-release 文件

release 文件通常被视为操作系统的标识。在 /etc 目录下放置了很多记录着发行版各种信息的文件,每个发行版都各自有一套这样记录着相关信息的文件。下面是一组在 Ubuntu/Debian 系统上显示出来的文件内容。

# cat /etc/issue
Ubuntu 16.04.3 LTS \n \l

# cat /etc/issue.net
Ubuntu 16.04.3 LTS

# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"

# cat /etc/os-release
NAME="Ubuntu"
VERSION="16.04.3 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.3 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial

# cat /etc/debian_version
9.3

下面这一组是在 RHEL/CentOS/Fedora 系统上显示出来的文件内容。其中 /etc/redhat-release/etc/system-release 文件是指向 /etc/[发行版名称]-release 文件的一个连接。

# cat /etc/centos-release
CentOS release 6.9 (Final)

# cat /etc/fedora-release
Fedora release 27 (Twenty Seven)

# cat /etc/os-release
NAME=Fedora
VERSION="27 (Twenty Seven)"
ID=fedora
VERSION_ID=27
PRETTY_NAME="Fedora 27 (Twenty Seven)"
ANSI_COLOR="0;34"
CPE_NAME="cpe:/o:fedoraproject:fedora:27"
HOME_URL="https://fedoraproject.org/"
SUPPORT_URL="https://fedoraproject.org/wiki/Communicating_and_getting_help"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=27
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=27
PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy"

# cat /etc/redhat-release
Fedora release 27 (Twenty Seven)

# cat /etc/system-release
Fedora release 27 (Twenty Seven)

方法 3: uname 命令

uname(unix name 的意思) 是一个打印系统信息的工具,包括内核名称、版本号、系统详细信息以及所运行的操作系统等等。

# uname -a
Linux localhost.localdomain 4.12.14-300.fc26.x86_64 #1 SMP Wed Sep 20 16:28:07 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

以上运行结果说明使用的操作系统版本是 Fedora 26。

方法 4: /proc/version 文件

这个文件记录了 Linux 内核的版本、用于编译内核的 gcc 的版本、内核编译的时间,以及内核编译者的用户名。

# cat /proc/version
Linux version 4.12.14-300.fc26.x86_64 ([email protected]) (gcc version 7.2.1 20170915 (Red Hat 7.2.1-2) (GCC) ) #1 SMP Wed Sep 20 16:28:07 UTC 2017

方法 5: dmesg 命令

dmesg( 展示信息 display message 驱动程序信息 driver message )是大多数类 Unix 操作系统上的一个命令,用于打印内核的消息缓冲区的信息。

# dmesg | grep "Linux"
[ 0.000000] Linux version 4.12.14-300.fc26.x86_64 ([email protected]) (gcc version 7.2.1 20170915 (Red Hat 7.2.1-2) (GCC) ) #1 SMP Wed Sep 20 16:28:07 UTC 2017
[ 0.001000] SELinux: Initializing.
[ 0.001000] SELinux: Starting in permissive mode
[ 0.470288] SELinux: Registering netfilter hooks
[ 0.616351] Linux agpgart interface v0.103
[ 0.630063] usb usb1: Manufacturer: Linux 4.12.14-300.fc26.x86_64 ehci_hcd
[ 0.688949] usb usb2: Manufacturer: Linux 4.12.14-300.fc26.x86_64 ohci_hcd
[ 2.564554] SELinux: Disabled at runtime.
[ 2.564584] SELinux: Unregistering netfilter hooks

方法 6: Yum/Dnf 命令

Yum( Yellowdog 更新器修改版 Yellowdog Updater Modified )是 Linux 操作系统上的一个包管理工具,而 yum 命令被用于一些基于 RedHat 的 Linux 发行版上安装、更新、查找、删除软件包。

# yum info nano
Loaded plugins: fastestmirror, ovl
Loading mirror speeds from cached hostfile
 * base: centos.zswap.net
 * extras: mirror2.evolution-host.com
 * updates: centos.zswap.net
Available Packages
Name : nano
Arch : x86_64
Version : 2.3.1
Release : 10.el7
Size : 440 k
Repo : base/7/x86_64
Summary : A small text editor
URL : http://www.nano-editor.org
License : GPLv3+
Description : GNU nano is a small and friendly text editor.

下面的 yum repolist 命令执行后显示了 yum 的基础源仓库、额外源仓库、更新源仓库都来自 CentOS 7 仓库。

# yum repolist
Loaded plugins: fastestmirror, ovl
Loading mirror speeds from cached hostfile
 * base: centos.zswap.net
 * extras: mirror2.evolution-host.com
 * updates: centos.zswap.net
repo id repo name status
base/7/x86_64 CentOS-7 - Base 9591
extras/7/x86_64 CentOS-7 - Extras 388
updates/7/x86_64 CentOS-7 - Updates 1929
repolist: 11908

使用 dnf 命令也同样可以查看发行版名称和版本号。

# dnf info nano
Last metadata expiration check: 0:01:25 ago on Thu Feb 15 01:59:31 2018.
Installed Packages
Name : nano
Version : 2.8.7
Release : 1.fc27
Arch : x86_64
Size : 2.1 M
Source : nano-2.8.7-1.fc27.src.rpm
Repo : @System
From repo : fedora
Summary : A small text editor
URL : https://www.nano-editor.org
License : GPLv3+
Description : GNU nano is a small and friendly text editor.

方法 7: RPM 命令

RPM( 红帽包管理器 RedHat Package Manager )是在 CentOS、Oracle Linux、Fedora 这些基于 RedHat 的操作系统上的一个强大的命令行包管理工具,同样也可以帮助我们查看系统的版本信息。

# rpm -q nano
nano-2.8.7-1.fc27.x86_64

方法 8: APT-GET 命令

Apt-Get( 高级打包工具 Advanced Packaging Tool )是一个强大的命令行工具,可以自动下载安装新软件包、更新已有的软件包、更新软件包列表索引,甚至更新整个 Debian 系统。

# apt-cache policy nano
nano:
 Installed: 2.5.3-2ubuntu2
 Candidate: 2.5.3-2ubuntu2
 Version table:
 * 2.5.3-2ubuntu2 500
 500 http://nova.clouds.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages
 100 /var/lib/dpkg/status
 2.5.3-2 500
 500 http://nova.clouds.archive.ubuntu.com/ubuntu xenial/main amd64 Packages

via: https://www.2daygeek.com/check-find-linux-distribution-name-and-version/

作者:Magesh Maruthamuthu 译者:HankChow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出