@shinyformica Correct - these string constants are actually global variables of type NSString *, which means that they contain a pointer to the actual string object.
To read the pointer from the global variable, you need to use ctypes.c_void_p.in_dll(objc_util.c, "ConstantName"), as @mikael already found above. objc_util.c.ConstantName will "work" (it doesn't crash), but that treats ConstantName as a function and not a variable, so it returns a function pointer (which will crash when you try to call it, because normal variables are not valid functions).
The value returned by in_dll is a regular Objective-C object pointer (which points to the NSString object), but as a c_void_p object, so you need to cast it to ObjCInstance manually so that you can use it. Once you do that, you have a regular NSString object with the value you're looking for.
In short:>>> objc_util.ObjCInstance(ctypes.c_void_p.in_dll(objc_util.c, 'UICollectionElementKindSectionHeader')) <b'__NSCFConstantString': UICollectionElementKindSectionHeader> >>> objc_util.ObjCInstance(ctypes.c_void_p.in_dll(objc_util.c, 'UICollectionElementKindSectionFooter')) <b'__NSCFConstantString': UICollectionElementKindSectionFooter>
Strangely, the value of both string constants is literally their name, so the approach suggested by @mikael (just pass the name of the constant as a string) should have worked. Maybe UIKit expects you to pass in the exact pointer, and not just any string with the same contents? (That would be quite strange though.)
(By the way, please do @-mention me if there's something where you think I can help. Sometimes I only skim the forums very quickly, so I might miss some questions by accident.)