⬆️ ⬇️

My fight with PTPCamera or the fascinating reversal story for the youngest

Almost all advanced SLR cameras, as well as some regular soap cases, allow you to control yourself from a computer. Software control of the camera provides interesting features, for example: shooting time lapse video , camera pairing with a microscope, experiments in computer vision. To control the camera vendors provide their own proprietary SDK, which usually work exclusively under Windows and support cameras only within a certain range (for example, Canon has as many as 4 incompatible SDKs). What a blessing that there is a worthy open alternative - the gphoto project.



Right now, gphoto supports 1598 camera models and the list is constantly growing. The project is built for all UNIX-like operating systems, including Linux and Mac OS X. Shooting can be managed both using the command line utility and from its own program using the libgphoto library. Bindings are available for different language platforms, including node.js.



In modern operating systems, there are built-in tools for working with digital cameras - as a rule, “work” means only uploading photos from the camera. These built-in mechanisms prevent the operation of gphoto, since they capture a USB device in exclusive mode. Particularly interesting is the situation in this regard in Mac OS X - the OS does not provide any standard features for shutting down, but the system of support for digital cameras is easily amenable to reverse engineering.

')

Scripts to block running PTPCamera on github.



PTPCamera

The Internet advises to execute the killall -9 PTPCamera (kill the PTPCamera process) after connecting the camera for gphoto to work properly. It really helps, but every time you connect the camera, you have to repeat the procedure again. Of course, you can simply remove the PTPCamera program, but I wanted to get by with a less radical solution.



In general, it was necessary to understand the mechanism for launching PTPCamera, and to disable this function as correctly as possible.



About capturing images on Mac OS X

According to the available sources [ 1 , 2 ], the image capture infrastructure in Mac OS X is organized as follows.







At the top of the stack are applications that the user directly interacts with (ex: iPhoto).



At the bottom are applications for managing devices, the latter include PTPCamera. Applications for managing devices ( MassStorageCamera.app , PTPCamera.app , TWAINBridge.app , etc.) live in the system /System/Library/Image Capture/Devices and /Library/Image Capture/Devices folders.



In the middle is the communication layer, which organizes the connection between the upper and lower levels. It is curious that several user applications can use one device together, and also transparent work with devices over a local network is possible.



Who launches PTPCamera?

Let's try to determine the mechanism for launching PTPCamera, and first define the parent process.

 $ pgrep PTPCamera 29045 $ ps -O ppid -p 29045 PID PPID TT STAT TIME COMMAND 29045 202 ?? S 0:00.10 /System/Library/Image Capture/Devices/PTPCamer $ ps -p 202 PID TTY TIME CMD 202 ?? 0:16.75 /sbin/launchd 


So we see that PTPCamera is launched by the launchd process. On Mac OS X, launchd is a universal launch for system and user daemons. The system has a launchd instance for each active user. The root user Launchd performs the same functions as init on traditional UNIX systems.



 $ ps -A -O user | grep /sbin/launchd 1 root ?? Ss 3:06.80 /sbin/launchd 172 _windowserver ?? Ss 0:00.06 /sbin/launchd 202 nickz ?? Ss 0:16.76 /sbin/launchd 206 _spotlight ?? Ss 0:00.27 /sbin/launchd 28919 _cvmsroot ?? Ss 0:00.01 /sbin/launchd 28937 _securityagent ?? Ss 0:00.01 /sbin/launchd 


In addition to demons, laucnhd also launches graphics applications at the command of other programs. PTPCamera is exactly the last case, as can be seen from the task ID in launchd, [prefix] tells us this.



 $ launchctl list | grep PTPCamera 29045 - [0x0-0x457457].com.apple.PTPCamera 


So, we know that PTPCamera was launched by the launchd process, at the command of some application X.



Turn on launchd logging ( launchctl log level debug ), and trigger PTPCamera to restart.



By default, a quota of 500 log entries per second is allocated for each process in the system. Messages that do not meet the limit are discarded. Set up a separate debug message build to bypass the limit.



Add a line to the /etc/syslog.conf file
 *.debug /var/log/debug.log 


and inform the syslogd daemon about the need to re-read the settings
 sudo killall -HUP syslogd 


Analyzing the resulting file debug.log . Find the required:
 ([0x0-0x2d92d9].com.apple.PTPCamera[24472]): Spawned by PID 240: com.apple.SystemUIServer.agent 


We request the launchd information about com.apple.SystemUIServer.agent :

 $ launchctl list com.apple.SystemUIServer.agent { "Program" = "/System/Library/CoreServices/SystemUIServer.app/Contents/MacOS/SystemUIServer"; }; 


Now we know that the “culprit” of launching PTPCamera is SystemUIServer , no less.



We pick SystemUIServer

There is a suspicion that the required functionality is not in SystemUIServer itself, but in one of the linked frameworks:

 $ otool -L /System/Library/CoreServices/SystemUIServer.app/Contents/MacOS/SystemUIServer /System/Library/CoreServices/SystemUIServer.app/Contents/MacOS/SystemUIServer: /System/Library/PrivateFrameworks/CoreUI.framework/Versions/A/CoreUI /System/Library/PrivateFrameworks/Admin.framework/Versions/A/Admin /System/Library/Frameworks/Carbon.framework/Versions/A/Carbon /System/Library/PrivateFrameworks/SystemUIPlugin.framework/Versions/A/SystemUIPlugin /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit /System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit /System/Library/Frameworks/Security.framework/Versions/A/Security /System/Library/PrivateFrameworks/ICANotifications.framework/Versions/A/ICANotifications /System/Library/PrivateFrameworks/iPod.framework/Versions/A/iPod ... 


In this list, the main suspect is ICANotifications.framework . ICA is short for image capture , the same acronym is used in public frameworks to capture images.



Learn ICANotifications.framework

Lyrical digression. The executable file consists of code and immutable static data (various constants, tables, and so on.) Of particular interest are string constants. You can extract them using the strings command.



Run strings /System/Library/PrivateFrameworks/ICANotifications.framework/Versions/A/ICANotifications , and enjoy the results:

 ... /Library/Caches/com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase.%d ... CREATE TABLE DBVersion (ID integer primary key not null, typeID integer, value integer) CREATE TABLE SourceFile (ID integer primary key not null, typeID integer, bundleID varchar(256), bundleVersion integer, bundlePath varchar(256), deviceDiscoveryPath varchar(256), deviceDiscoveryModDate varchar(20), readDate varchar(20), iTWAINDS integer) CREATE TABLE IOUSBDevice (ID integer primary key not null, typeID integer, idVendor integer, idProduct integer) CREATE TABLE IOUSBInterface (ID integer primary key not null, typeID integer, bInterfaceClass integer, bInterfaceSubClass integer, bInterfaceProtocol integer) ... 


So it is SQL!



So, the working hypothesis - the library works with the SQLite database, most likely it is the file com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase in /Library/Caches .



 $ ls /Library/Caches/com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase.* /Library/Caches/com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase.501 $ sqlite3 /Library/Caches/com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase.501 sqlite> .schema CREATE TABLE DBVersion (ID integer primary key not null, typeID integer, value integer); CREATE TABLE IOUSBDevice (ID integer primary key not null, typeID integer, idVendor integer, idProduct integer); CREATE TABLE IOUSBInterface (ID integer primary key not null, typeID integer, bInterfaceClass integer, bInterfaceSubClass integer, bInterfaceProtocol integer); ... 


And there is!



You can see that the user ID is appended to the end of the name ( com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase.501 ), each user has its own file. From the content it is clear that the base sets the list of correspondences of the class of devices and the control program that must be launched when a device is detected.



Editing the database, we disable the launch of PTPCamera for any selected user, this is an unambiguous success !



If you need to return everything back, roll back the changes, or simply delete the database file (the name of the /Library/Caches tells us that the OS can regenerate the contents if necessary).



Further - the matter of technology.



Optional materials

  1. Amit Singh Mac OS X Internals: A Systems Approach [ amazon ]
  2. Project repository

Source: https://habr.com/ru/post/173323/



All Articles